1 #define PETSCKSP_DLL 2 3 /* 4 Defines a preconditioner that can consist of a collection of PCs 5 */ 6 #include "src/ksp/pc/pcimpl.h" /*I "petscpc.h" I*/ 7 #include "petscksp.h" /*I "petscksp.h" I*/ 8 9 typedef struct _PC_CompositeLink *PC_CompositeLink; 10 struct _PC_CompositeLink { 11 PC pc; 12 PC_CompositeLink next; 13 }; 14 15 typedef struct { 16 PC_CompositeLink head; 17 PCCompositeType type; 18 Vec work1; 19 Vec work2; 20 PetscScalar alpha; 21 PetscTruth use_true_matrix; 22 } PC_Composite; 23 24 #undef __FUNCT__ 25 #define __FUNCT__ "PCApply_Composite_Multiplicative" 26 static PetscErrorCode PCApply_Composite_Multiplicative(PC pc,Vec x,Vec y) 27 { 28 PetscErrorCode ierr; 29 PC_Composite *jac = (PC_Composite*)pc->data; 30 PC_CompositeLink next = jac->head; 31 Mat mat = pc->pmat; 32 33 PetscFunctionBegin; 34 if (!next) { 35 SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"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);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(jac->work2,-1.0,jac->work1,x);CHKERRQ(ierr); 46 ierr = PCApply(next->pc,jac->work2,jac->work1);CHKERRQ(ierr); 47 ierr = VecAXPY(y,1.0,jac->work1);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 PetscErrorCode PCApply_Composite_Special(PC pc,Vec x,Vec y) 61 { 62 PetscErrorCode ierr; 63 PC_Composite *jac = (PC_Composite*)pc->data; 64 PC_CompositeLink next = jac->head; 65 66 PetscFunctionBegin; 67 if (!next) { 68 SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC()"); 69 } 70 if (!next->next || next->next->next) { 71 SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Special composite preconditioners requires exactly two PCs"); 72 } 73 74 ierr = PCApply(next->pc,x,jac->work1);CHKERRQ(ierr); 75 ierr = PCApply(next->next->pc,jac->work1,y);CHKERRQ(ierr); 76 PetscFunctionReturn(0); 77 } 78 79 #undef __FUNCT__ 80 #define __FUNCT__ "PCApply_Composite_Additive" 81 static PetscErrorCode PCApply_Composite_Additive(PC pc,Vec x,Vec y) 82 { 83 PetscErrorCode ierr; 84 PC_Composite *jac = (PC_Composite*)pc->data; 85 PC_CompositeLink next = jac->head; 86 87 PetscFunctionBegin; 88 if (!next) { 89 SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"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(y,1.0,jac->work1);CHKERRQ(ierr); 96 } 97 PetscFunctionReturn(0); 98 } 99 100 #undef __FUNCT__ 101 #define __FUNCT__ "PCSetUp_Composite" 102 static PetscErrorCode PCSetUp_Composite(PC pc) 103 { 104 PetscErrorCode 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 PetscErrorCode PCDestroy_Composite(PC pc) 123 { 124 PC_Composite *jac = (PC_Composite*)pc->data; 125 PetscErrorCode 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 PetscErrorCode PCSetFromOptions_Composite(PC pc) 143 { 144 PC_Composite *jac = (PC_Composite*)pc->data; 145 PetscErrorCode ierr; 146 PetscInt nmax = 8,i; 147 PC_CompositeLink next; 148 char *pcs[8]; 149 PetscTruth flg; 150 151 PetscFunctionBegin; 152 ierr = PetscOptionsHead("Composite preconditioner options");CHKERRQ(ierr); 153 ierr = PetscOptionsEnum("-pc_composite_type","Type of composition","PCCompositeSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);CHKERRQ(ierr); 154 ierr = PetscOptionsName("-pc_composite_true","Use true matrix for inner solves","PCCompositeSetUseTrue",&flg);CHKERRQ(ierr); 155 if (flg) { 156 ierr = PCCompositeSetUseTrue(pc);CHKERRQ(ierr); 157 } 158 ierr = PetscOptionsStringArray("-pc_composite_pcs","List of composite solvers","PCCompositeAddPC",pcs,&nmax,&flg);CHKERRQ(ierr); 159 if (flg) { 160 for (i=0; i<nmax; i++) { 161 ierr = PCCompositeAddPC(pc,pcs[i]);CHKERRQ(ierr); 162 } 163 } 164 ierr = PetscOptionsTail();CHKERRQ(ierr); 165 166 next = jac->head; 167 while (next) { 168 ierr = PCSetFromOptions(next->pc);CHKERRQ(ierr); 169 next = next->next; 170 } 171 PetscFunctionReturn(0); 172 } 173 174 #undef __FUNCT__ 175 #define __FUNCT__ "PCView_Composite" 176 static PetscErrorCode PCView_Composite(PC pc,PetscViewer viewer) 177 { 178 PC_Composite *jac = (PC_Composite*)pc->data; 179 PetscErrorCode ierr; 180 PC_CompositeLink next = jac->head; 181 PetscTruth iascii; 182 183 PetscFunctionBegin; 184 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 185 if (iascii) { 186 ierr = PetscViewerASCIIPrintf(viewer,"Composite PC type - %s\n",PCCompositeTypes[jac->type]);CHKERRQ(ierr); 187 ierr = PetscViewerASCIIPrintf(viewer,"PCs on composite preconditioner follow\n");CHKERRQ(ierr); 188 ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr); 189 } else { 190 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCComposite",((PetscObject)viewer)->type_name); 191 } 192 if (iascii) { 193 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 194 } 195 while (next) { 196 ierr = PCView(next->pc,viewer);CHKERRQ(ierr); 197 next = next->next; 198 } 199 if (iascii) { 200 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 201 ierr = PetscViewerASCIIPrintf(viewer,"---------------------------------\n");CHKERRQ(ierr); 202 } 203 PetscFunctionReturn(0); 204 } 205 206 /* ------------------------------------------------------------------------------*/ 207 208 EXTERN_C_BEGIN 209 #undef __FUNCT__ 210 #define __FUNCT__ "PCCompositeSpecialSetAlpha_Composite" 211 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSpecialSetAlpha_Composite(PC pc,PetscScalar alpha) 212 { 213 PC_Composite *jac = (PC_Composite*)pc->data; 214 PetscFunctionBegin; 215 jac->alpha = alpha; 216 PetscFunctionReturn(0); 217 } 218 EXTERN_C_END 219 220 EXTERN_C_BEGIN 221 #undef __FUNCT__ 222 #define __FUNCT__ "PCCompositeSetType_Composite" 223 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSetType_Composite(PC pc,PCCompositeType type) 224 { 225 PetscFunctionBegin; 226 if (type == PC_COMPOSITE_ADDITIVE) { 227 pc->ops->apply = PCApply_Composite_Additive; 228 } else if (type == PC_COMPOSITE_MULTIPLICATIVE) { 229 pc->ops->apply = PCApply_Composite_Multiplicative; 230 } else if (type == PC_COMPOSITE_SPECIAL) { 231 pc->ops->apply = PCApply_Composite_Special; 232 } else { 233 SETERRQ(PETSC_ERR_ARG_WRONG,"Unkown composite preconditioner type"); 234 } 235 PetscFunctionReturn(0); 236 } 237 EXTERN_C_END 238 239 EXTERN_C_BEGIN 240 #undef __FUNCT__ 241 #define __FUNCT__ "PCCompositeAddPC_Composite" 242 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeAddPC_Composite(PC pc,PCType type) 243 { 244 PC_Composite *jac; 245 PC_CompositeLink next,ilink; 246 PetscErrorCode ierr; 247 PetscInt cnt = 0; 248 const char *prefix; 249 char newprefix[8]; 250 251 PetscFunctionBegin; 252 ierr = PetscNew(struct _PC_CompositeLink,&ilink);CHKERRQ(ierr); 253 ilink->next = 0; 254 ierr = PCCreate(pc->comm,&ilink->pc);CHKERRQ(ierr); 255 256 jac = (PC_Composite*)pc->data; 257 next = jac->head; 258 if (!next) { 259 jac->head = ilink; 260 } else { 261 cnt++; 262 while (next->next) { 263 next = next->next; 264 cnt++; 265 } 266 next->next = ilink; 267 } 268 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 269 ierr = PCSetOptionsPrefix(ilink->pc,prefix);CHKERRQ(ierr); 270 sprintf(newprefix,"sub_%d_",(int)cnt); 271 ierr = PCAppendOptionsPrefix(ilink->pc,newprefix);CHKERRQ(ierr); 272 /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */ 273 ierr = PCSetType(ilink->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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeGetPC_Composite(PC pc,PetscInt n,PC *subpc) 283 { 284 PC_Composite *jac; 285 PC_CompositeLink next; 286 PetscInt 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(PETSC_ERR_ARG_INCOMP,"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 PetscErrorCode PETSCKSP_DLLEXPORT 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 /*@ 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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSetType(PC pc,PCCompositeType type) 336 { 337 PetscErrorCode 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 /*@ 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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSpecialSetAlpha(PC pc,PetscScalar alpha) 365 { 366 PetscErrorCode 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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeAddPC(PC pc,PCType type) 393 { 394 PetscErrorCode 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 /*@ 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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeGetPC(PC pc,PetscInt n,PC *subpc) 426 { 427 PetscErrorCode ierr,(*f)(PC,PetscInt,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(PETSC_ERR_ARG_WRONG,"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 PetscErrorCode PETSCKSP_DLLEXPORT PCCompositeSetUseTrue(PC pc) 467 { 468 PetscErrorCode 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 outter 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 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_Composite(PC pc) 508 { 509 PetscErrorCode ierr; 510 PC_Composite *jac; 511 512 PetscFunctionBegin; 513 ierr = PetscNew(PC_Composite,&jac);CHKERRQ(ierr); 514 ierr = PetscLogObjectMemory(pc,sizeof(PC_Composite));CHKERRQ(ierr); 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