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