1 /*$Id: composite.c,v 1.45 2001/08/07 03:03:39 balay Exp $*/ 2 /* 3 Defines a preconditioner that can consist of a collection of PCs 4 */ 5 #include "src/ksp/pc/pcimpl.h" /*I "petscpc.h" I*/ 6 #include "petscksp.h" /*I "petscksp.h" I*/ 7 8 typedef struct _PC_CompositeLink *PC_CompositeLink; 9 struct _PC_CompositeLink { 10 PC pc; 11 PC_CompositeLink next; 12 }; 13 14 typedef struct { 15 PC_CompositeLink head; 16 PCCompositeType type; 17 Vec work1; 18 Vec work2; 19 PetscScalar alpha; 20 PetscTruth use_true_matrix; 21 } PC_Composite; 22 23 #undef __FUNCT__ 24 #define __FUNCT__ "PCApply_Composite_Multiplicative" 25 static int PCApply_Composite_Multiplicative(PC pc,Vec x,Vec y) 26 { 27 int ierr; 28 PC_Composite *jac = (PC_Composite*)pc->data; 29 PC_CompositeLink next = jac->head; 30 PetscScalar one = 1.0,mone = -1.0; 31 Mat mat = pc->pmat; 32 33 PetscFunctionBegin; 34 if (!next) { 35 SETERRQ(1,"No composite preconditioners supplied via PCCompositeAddPC()"); 36 } 37 if (next->next && !jac->work2) { /* allocate second work vector */ 38 ierr = VecDuplicate(jac->work1,&jac->work2);CHKERRQ(ierr); 39 } 40 ierr = PCApply(next->pc,x,y,PC_LEFT);CHKERRQ(ierr); 41 if (jac->use_true_matrix) mat = pc->mat; 42 while (next->next) { 43 next = next->next; 44 ierr = MatMult(mat,y,jac->work1);CHKERRQ(ierr); 45 ierr = VecWAXPY(&mone,jac->work1,x,jac->work2);CHKERRQ(ierr); 46 ierr = PCApply(next->pc,jac->work2,jac->work1,PC_LEFT);CHKERRQ(ierr); 47 ierr = VecAXPY(&one,jac->work1,y);CHKERRQ(ierr); 48 } 49 50 PetscFunctionReturn(0); 51 } 52 53 /* 54 This is very special for a matrix of the form alpha I + R + S 55 where first preconditioner is built from alpha I + S and second from 56 alpha I + R 57 */ 58 #undef __FUNCT__ 59 #define __FUNCT__ "PCApply_Composite_Special" 60 static int PCApply_Composite_Special(PC pc,Vec x,Vec y) 61 { 62 int ierr; 63 PC_Composite *jac = (PC_Composite*)pc->data; 64 PC_CompositeLink next = jac->head; 65 66 PetscFunctionBegin; 67 if (!next) { 68 SETERRQ(1,"No composite preconditioners supplied via PCCompositeAddPC()"); 69 } 70 if (!next->next || next->next->next) { 71 SETERRQ(1,"Special composite preconditioners requires exactly two PCs"); 72 } 73 74 ierr = PCApply(next->pc,x,jac->work1,PC_LEFT);CHKERRQ(ierr); 75 ierr = PCApply(next->next->pc,jac->work1,y,PC_LEFT);CHKERRQ(ierr); 76 PetscFunctionReturn(0); 77 } 78 79 #undef __FUNCT__ 80 #define __FUNCT__ "PCApply_Composite_Additive" 81 static int PCApply_Composite_Additive(PC pc,Vec x,Vec y) 82 { 83 int ierr; 84 PC_Composite *jac = (PC_Composite*)pc->data; 85 PC_CompositeLink next = jac->head; 86 PetscScalar one = 1.0; 87 88 PetscFunctionBegin; 89 if (!next) { 90 SETERRQ(1,"No composite preconditioners supplied via PCCompositeAddPC()"); 91 } 92 ierr = PCApply(next->pc,x,y,PC_LEFT);CHKERRQ(ierr); 93 while (next->next) { 94 next = next->next; 95 ierr = PCApply(next->pc,x,jac->work1,PC_LEFT);CHKERRQ(ierr); 96 ierr = VecAXPY(&one,jac->work1,y);CHKERRQ(ierr); 97 } 98 PetscFunctionReturn(0); 99 } 100 101 #undef __FUNCT__ 102 #define __FUNCT__ "PCSetUp_Composite" 103 static int PCSetUp_Composite(PC pc) 104 { 105 int ierr; 106 PC_Composite *jac = (PC_Composite*)pc->data; 107 PC_CompositeLink next = jac->head; 108 109 PetscFunctionBegin; 110 if (!jac->work1) { 111 ierr = VecDuplicate(pc->vec,&jac->work1);CHKERRQ(ierr); 112 } 113 while (next) { 114 ierr = PCSetOperators(next->pc,pc->mat,pc->pmat,pc->flag);CHKERRQ(ierr); 115 ierr = PCSetVector(next->pc,jac->work1);CHKERRQ(ierr); 116 next = next->next; 117 } 118 119 PetscFunctionReturn(0); 120 } 121 122 #undef __FUNCT__ 123 #define __FUNCT__ "PCDestroy_Composite" 124 static int PCDestroy_Composite(PC pc) 125 { 126 PC_Composite *jac = (PC_Composite*)pc->data; 127 int ierr; 128 PC_CompositeLink next = jac->head; 129 130 PetscFunctionBegin; 131 while (next) { 132 ierr = PCDestroy(next->pc);CHKERRQ(ierr); 133 next = next->next; 134 } 135 136 if (jac->work1) {ierr = VecDestroy(jac->work1);CHKERRQ(ierr);} 137 if (jac->work2) {ierr = VecDestroy(jac->work2);CHKERRQ(ierr);} 138 ierr = PetscFree(jac);CHKERRQ(ierr); 139 PetscFunctionReturn(0); 140 } 141 142 #undef __FUNCT__ 143 #define __FUNCT__ "PCSetFromOptions_Composite" 144 static int PCSetFromOptions_Composite(PC pc) 145 { 146 PC_Composite *jac = (PC_Composite*)pc->data; 147 int ierr,nmax = 8,i,indx; 148 PC_CompositeLink next; 149 char *pcs[8]; 150 const char *types[] = {"multiplicative","additive","special"}; 151 PetscTruth flg; 152 153 PetscFunctionBegin; 154 ierr = PetscOptionsHead("Composite preconditioner options");CHKERRQ(ierr); 155 ierr = PetscOptionsEList("-pc_composite_type","Type of composition","PCCompositeSetType",types,3,types[0],&indx,&flg);CHKERRQ(ierr); 156 if (flg) { 157 ierr = PCCompositeSetType(pc,(PCCompositeType)indx);CHKERRQ(ierr); 158 } 159 ierr = PetscOptionsName("-pc_composite_true","Use true matrix for inner solves","PCCompositeSetUseTrue",&flg);CHKERRQ(ierr); 160 if (flg) { 161 ierr = PCCompositeSetUseTrue(pc);CHKERRQ(ierr); 162 } 163 ierr = PetscOptionsStringArray("-pc_composite_pcs","List of composite solvers","PCCompositeAddPC",pcs,&nmax,&flg);CHKERRQ(ierr); 164 if (flg) { 165 for (i=0; i<nmax; i++) { 166 ierr = PCCompositeAddPC(pc,pcs[i]);CHKERRQ(ierr); 167 } 168 } 169 ierr = PetscOptionsTail();CHKERRQ(ierr); 170 171 next = jac->head; 172 while (next) { 173 ierr = PCSetFromOptions(next->pc);CHKERRQ(ierr); 174 next = next->next; 175 } 176 PetscFunctionReturn(0); 177 } 178 179 #undef __FUNCT__ 180 #define __FUNCT__ "PCView_Composite" 181 static int PCView_Composite(PC pc,PetscViewer viewer) 182 { 183 PC_Composite *jac = (PC_Composite*)pc->data; 184 int ierr; 185 PC_CompositeLink next = jac->head; 186 PetscTruth isascii; 187 188 PetscFunctionBegin; 189 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&isascii);CHKERRQ(ierr); 190 if (isascii) { 191 ierr = PetscViewerASCIIPrintf(viewer,"PCs on composite preconditioner follow\n");CHKERRQ(ierr); 192 ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr); 193 } else { 194 SETERRQ1(1,"Viewer type %s not supported for PCComposite",((PetscObject)viewer)->type_name); 195 } 196 if (isascii) { 197 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 198 } 199 while (next) { 200 ierr = PCView(next->pc,viewer);CHKERRQ(ierr); 201 next = next->next; 202 } 203 if (isascii) { 204 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 205 ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr); 206 } 207 PetscFunctionReturn(0); 208 } 209 210 /* ------------------------------------------------------------------------------*/ 211 212 EXTERN_C_BEGIN 213 #undef __FUNCT__ 214 #define __FUNCT__ "PCCompositeSpecialSetAlpha_Composite" 215 int PCCompositeSpecialSetAlpha_Composite(PC pc,PetscScalar alpha) 216 { 217 PC_Composite *jac = (PC_Composite*)pc->data; 218 PetscFunctionBegin; 219 jac->alpha = alpha; 220 PetscFunctionReturn(0); 221 } 222 EXTERN_C_END 223 224 EXTERN_C_BEGIN 225 #undef __FUNCT__ 226 #define __FUNCT__ "PCCompositeSetType_Composite" 227 int PCCompositeSetType_Composite(PC pc,PCCompositeType type) 228 { 229 PetscFunctionBegin; 230 if (type == PC_COMPOSITE_ADDITIVE) { 231 pc->ops->apply = PCApply_Composite_Additive; 232 } else if (type == PC_COMPOSITE_MULTIPLICATIVE) { 233 pc->ops->apply = PCApply_Composite_Multiplicative; 234 } else if (type == PC_COMPOSITE_SPECIAL) { 235 pc->ops->apply = PCApply_Composite_Special; 236 } else { 237 SETERRQ(1,"Unkown composite preconditioner type"); 238 } 239 PetscFunctionReturn(0); 240 } 241 EXTERN_C_END 242 243 EXTERN_C_BEGIN 244 #undef __FUNCT__ 245 #define __FUNCT__ "PCCompositeAddPC_Composite" 246 int PCCompositeAddPC_Composite(PC pc,PCType type) 247 { 248 PC_Composite *jac; 249 PC_CompositeLink next,link; 250 int ierr,cnt = 0; 251 char *prefix,newprefix[8]; 252 253 PetscFunctionBegin; 254 ierr = PetscNew(struct _PC_CompositeLink,&link);CHKERRQ(ierr); 255 link->next = 0; 256 ierr = PCCreate(pc->comm,&link->pc);CHKERRQ(ierr); 257 258 jac = (PC_Composite*)pc->data; 259 next = jac->head; 260 if (!next) { 261 jac->head = link; 262 } else { 263 cnt++; 264 while (next->next) { 265 next = next->next; 266 cnt++; 267 } 268 next->next = link; 269 } 270 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 271 ierr = PCSetOptionsPrefix(link->pc,prefix);CHKERRQ(ierr); 272 sprintf(newprefix,"sub_%d_",cnt); 273 ierr = PCAppendOptionsPrefix(link->pc,newprefix);CHKERRQ(ierr); 274 /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */ 275 ierr = PCSetType(link->pc,type);CHKERRQ(ierr); 276 277 PetscFunctionReturn(0); 278 } 279 EXTERN_C_END 280 281 EXTERN_C_BEGIN 282 #undef __FUNCT__ 283 #define __FUNCT__ "PCCompositeGetPC_Composite" 284 int PCCompositeGetPC_Composite(PC pc,int n,PC *subpc) 285 { 286 PC_Composite *jac; 287 PC_CompositeLink next; 288 int i; 289 290 PetscFunctionBegin; 291 jac = (PC_Composite*)pc->data; 292 next = jac->head; 293 for (i=0; i<n; i++) { 294 if (!next->next) { 295 SETERRQ(1,"Not enough PCs in composite preconditioner"); 296 } 297 next = next->next; 298 } 299 *subpc = next->pc; 300 PetscFunctionReturn(0); 301 } 302 EXTERN_C_END 303 304 EXTERN_C_BEGIN 305 #undef __FUNCT__ 306 #define __FUNCT__ "PCCompositeSetUseTrue_Composite" 307 int PCCompositeSetUseTrue_Composite(PC pc) 308 { 309 PC_Composite *jac; 310 311 PetscFunctionBegin; 312 jac = (PC_Composite*)pc->data; 313 jac->use_true_matrix = PETSC_TRUE; 314 PetscFunctionReturn(0); 315 } 316 EXTERN_C_END 317 318 /* -------------------------------------------------------------------------------- */ 319 #undef __FUNCT__ 320 #define __FUNCT__ "PCCompositeSetType" 321 /*@C 322 PCCompositeSetType - Sets the type of composite preconditioner. 323 324 Collective on PC 325 326 Input Parameter: 327 . pc - the preconditioner context 328 . type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL 329 330 Options Database Key: 331 . -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type 332 333 Level: Developer 334 335 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 336 @*/ 337 int PCCompositeSetType(PC pc,PCCompositeType type) 338 { 339 int ierr,(*f)(PC,PCCompositeType); 340 341 PetscFunctionBegin; 342 PetscValidHeaderSpecific(pc,PC_COOKIE); 343 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeSetType_C",(void (**)(void))&f);CHKERRQ(ierr); 344 if (f) { 345 ierr = (*f)(pc,type);CHKERRQ(ierr); 346 } 347 PetscFunctionReturn(0); 348 } 349 350 #undef __FUNCT__ 351 #define __FUNCT__ "PCCompositeSpecialSetAlpha" 352 /*@C 353 PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner 354 for alphaI + R + S 355 356 Collective on PC 357 358 Input Parameter: 359 + pc - the preconditioner context 360 - alpha - scale on identity 361 362 Level: Developer 363 364 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 365 @*/ 366 int PCCompositeSpecialSetAlpha(PC pc,PetscScalar alpha) 367 { 368 int ierr,(*f)(PC,PetscScalar); 369 370 PetscFunctionBegin; 371 PetscValidHeaderSpecific(pc,PC_COOKIE); 372 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeSpecialSetAlpha_C",(void (**)(void))&f);CHKERRQ(ierr); 373 if (f) { 374 ierr = (*f)(pc,alpha);CHKERRQ(ierr); 375 } 376 PetscFunctionReturn(0); 377 } 378 379 #undef __FUNCT__ 380 #define __FUNCT__ "PCCompositeAddPC" 381 /*@C 382 PCCompositeAddPC - Adds another PC to the composite PC. 383 384 Collective on PC 385 386 Input Parameters: 387 . pc - the preconditioner context 388 . type - the type of the new preconditioner 389 390 Level: Developer 391 392 .keywords: PC, composite preconditioner, add 393 @*/ 394 int PCCompositeAddPC(PC pc,PCType type) 395 { 396 int ierr,(*f)(PC,PCType); 397 398 PetscFunctionBegin; 399 PetscValidHeaderSpecific(pc,PC_COOKIE); 400 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeAddPC_C",(void (**)(void))&f);CHKERRQ(ierr); 401 if (f) { 402 ierr = (*f)(pc,type);CHKERRQ(ierr); 403 } 404 PetscFunctionReturn(0); 405 } 406 407 #undef __FUNCT__ 408 #define __FUNCT__ "PCCompositeGetPC" 409 /*@C 410 PCCompositeGetPC - Gets one of the PC objects in the composite PC. 411 412 Not Collective 413 414 Input Parameter: 415 . pc - the preconditioner context 416 . n - the number of the pc requested 417 418 Output Parameters: 419 . subpc - the PC requested 420 421 Level: Developer 422 423 .keywords: PC, get, composite preconditioner, sub preconditioner 424 425 .seealso: PCCompositeAddPC() 426 @*/ 427 int PCCompositeGetPC(PC pc,int n,PC *subpc) 428 { 429 int ierr,(*f)(PC,int,PC *); 430 431 PetscFunctionBegin; 432 PetscValidHeaderSpecific(pc,PC_COOKIE); 433 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeGetPC_C",(void (**)(void))&f);CHKERRQ(ierr); 434 if (f) { 435 ierr = (*f)(pc,n,subpc);CHKERRQ(ierr); 436 } else { 437 SETERRQ(1,"Cannot get pc, not composite type"); 438 } 439 PetscFunctionReturn(0); 440 } 441 442 #undef __FUNCT__ 443 #define __FUNCT__ "PCCompositeSetUseTrue" 444 /*@ 445 PCCompositeSetUseTrue - Sets a flag to indicate that the true matrix (rather than 446 the matrix used to define the preconditioner) is used to compute 447 the residual when the multiplicative scheme is used. 448 449 Collective on PC 450 451 Input Parameters: 452 . pc - the preconditioner context 453 454 Options Database Key: 455 . -pc_composite_true - Activates PCCompositeSetUseTrue() 456 457 Note: 458 For the common case in which the preconditioning and linear 459 system matrices are identical, this routine is unnecessary. 460 461 Level: Developer 462 463 .keywords: PC, composite preconditioner, set, true, flag 464 465 .seealso: PCSetOperators(), PCBJacobiSetUseTrueLocal(), PCKSPSetUseTrue() 466 @*/ 467 int PCCompositeSetUseTrue(PC pc) 468 { 469 int ierr,(*f)(PC); 470 471 PetscFunctionBegin; 472 PetscValidHeaderSpecific(pc,PC_COOKIE); 473 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCCompositeSetUseTrue_C",(void (**)(void))&f);CHKERRQ(ierr); 474 if (f) { 475 ierr = (*f)(pc);CHKERRQ(ierr); 476 } 477 PetscFunctionReturn(0); 478 } 479 480 /* -------------------------------------------------------------------------------------------*/ 481 482 /*MC 483 PCCOMPOSITE - Build a preconditioner by composing together several preconditioners 484 485 Options Database Keys: 486 . -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type 487 . -pc_composite_true - Activates PCCompositeSetUseTrue() 488 489 Level: intermediate 490 491 Concepts: composing solvers 492 493 Notes: To use a Krylov method inside the composite preconditioner, set the PCType of one or more 494 inner PCs to be PCKSP. 495 Using a Krylov method inside another Krylov method can be dangerous (you get divergence or 496 the incorrect answer) unless you use KSPFGMRES as the other Krylov method 497 498 499 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, 500 PCSHELL, PCKSP, PCCompositeSetType(), PCCompositeSpecialSetAlpha(), PCCompositeAddPC(), 501 PCCompositeGetPC(), PCCompositeSetUseTrue() 502 503 M*/ 504 505 EXTERN_C_BEGIN 506 #undef __FUNCT__ 507 #define __FUNCT__ "PCCreate_Composite" 508 int PCCreate_Composite(PC pc) 509 { 510 int ierr; 511 PC_Composite *jac; 512 513 PetscFunctionBegin; 514 ierr = PetscNew(PC_Composite,&jac);CHKERRQ(ierr); 515 PetscLogObjectMemory(pc,sizeof(PC_Composite)); 516 pc->ops->apply = PCApply_Composite_Additive; 517 pc->ops->setup = PCSetUp_Composite; 518 pc->ops->destroy = PCDestroy_Composite; 519 pc->ops->setfromoptions = PCSetFromOptions_Composite; 520 pc->ops->view = PCView_Composite; 521 pc->ops->applyrichardson = 0; 522 523 pc->data = (void*)jac; 524 jac->type = PC_COMPOSITE_ADDITIVE; 525 jac->work1 = 0; 526 jac->work2 = 0; 527 jac->head = 0; 528 529 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSetType_C","PCCompositeSetType_Composite", 530 PCCompositeSetType_Composite);CHKERRQ(ierr); 531 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeAddPC_C","PCCompositeAddPC_Composite", 532 PCCompositeAddPC_Composite);CHKERRQ(ierr); 533 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeGetPC_C","PCCompositeGetPC_Composite", 534 PCCompositeGetPC_Composite);CHKERRQ(ierr); 535 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSetUseTrue_C","PCCompositeSetUseTrue_Composite", 536 PCCompositeSetUseTrue_Composite);CHKERRQ(ierr); 537 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSpecialSetAlpha_C","PCCompositeSpecialSetAlpha_Composite", 538 PCCompositeSpecialSetAlpha_Composite);CHKERRQ(ierr); 539 540 PetscFunctionReturn(0); 541 } 542 EXTERN_C_END 543 544