Actual source code: composite.c

  2: /*
  3:       Defines a preconditioner that can consist of a collection of PCs
  4: */
  5: #include <private/pcimpl.h>   /*I "petscpc.h" I*/
  6: #include <petscksp.h>            /*I "petscksp.h" I*/

  8: typedef struct _PC_CompositeLink *PC_CompositeLink;
  9: struct _PC_CompositeLink {
 10:   PC               pc;
 11:   PC_CompositeLink next;
 12:   PC_CompositeLink previous;
 13: };
 14: 
 15: typedef struct {
 16:   PC_CompositeLink head;
 17:   PCCompositeType  type;
 18:   Vec              work1;
 19:   Vec              work2;
 20:   PetscScalar      alpha;
 21:   PetscBool        use_true_matrix;
 22: } PC_Composite;

 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;

 34:   if (!next) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
 35:   if (next->next && !jac->work2) { /* allocate second work vector */
 36:     VecDuplicate(jac->work1,&jac->work2);
 37:   }
 38:   if (jac->use_true_matrix) mat = pc->mat;
 39:   PCApply(next->pc,x,y);
 40:   while (next->next) {
 41:     next = next->next;
 42:     MatMult(mat,y,jac->work1);
 43:     VecWAXPY(jac->work2,-1.0,jac->work1,x);
 44:     VecSet(jac->work1,0.0);  /* zero since some PC's may not set all entries in the result */
 45:     PCApply(next->pc,jac->work2,jac->work1);
 46:     VecAXPY(y,1.0,jac->work1);
 47:   }
 48:   if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
 49:     while (next->previous) {
 50:       next = next->previous;
 51:       MatMult(mat,y,jac->work1);
 52:       VecWAXPY(jac->work2,-1.0,jac->work1,x);
 53:       VecSet(jac->work1,0.0);  /* zero since some PC's may not set all entries in the result */
 54:       PCApply(next->pc,jac->work2,jac->work1);
 55:       VecAXPY(y,1.0,jac->work1);
 56:     }
 57:   }
 58:   return(0);
 59: }

 63: static PetscErrorCode PCApplyTranspose_Composite_Multiplicative(PC pc,Vec x,Vec y)
 64: {
 65:   PetscErrorCode   ierr;
 66:   PC_Composite     *jac = (PC_Composite*)pc->data;
 67:   PC_CompositeLink next = jac->head;
 68:   Mat              mat = pc->pmat;

 71:   if (!next) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
 72:   if (next->next && !jac->work2) { /* allocate second work vector */
 73:     VecDuplicate(jac->work1,&jac->work2);
 74:   }
 75:   if (jac->use_true_matrix) mat = pc->mat;
 76:   /* locate last PC */
 77:   while (next->next) {
 78:     next = next->next;
 79:   }
 80:   PCApplyTranspose(next->pc,x,y);
 81:   while (next->previous) {
 82:     next = next->previous;
 83:     MatMultTranspose(mat,y,jac->work1);
 84:     VecWAXPY(jac->work2,-1.0,jac->work1,x);
 85:     VecSet(jac->work1,0.0);  /* zero since some PC's may not set all entries in the result */
 86:     PCApplyTranspose(next->pc,jac->work2,jac->work1);
 87:     VecAXPY(y,1.0,jac->work1);
 88:   }
 89:   if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
 90:     next = jac->head;
 91:     while (next->next) {
 92:       next = next->next;
 93:       MatMultTranspose(mat,y,jac->work1);
 94:       VecWAXPY(jac->work2,-1.0,jac->work1,x);
 95:       VecSet(jac->work1,0.0);  /* zero since some PC's may not set all entries in the result */
 96:       PCApplyTranspose(next->pc,jac->work2,jac->work1);
 97:       VecAXPY(y,1.0,jac->work1);
 98:     }
 99:   }
100:   return(0);
101: }

103: /*
104:     This is very special for a matrix of the form alpha I + R + S
105: where first preconditioner is built from alpha I + S and second from
106: alpha I + R
107: */
110: static PetscErrorCode PCApply_Composite_Special(PC pc,Vec x,Vec y)
111: {
112:   PetscErrorCode   ierr;
113:   PC_Composite     *jac = (PC_Composite*)pc->data;
114:   PC_CompositeLink next = jac->head;

117:   if (!next) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
118:   if (!next->next || next->next->next) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Special composite preconditioners requires exactly two PCs");

120:   PCApply(next->pc,x,jac->work1);
121:   PCApply(next->next->pc,jac->work1,y);
122:   return(0);
123: }

127: static PetscErrorCode PCApply_Composite_Additive(PC pc,Vec x,Vec y)
128: {
129:   PetscErrorCode   ierr;
130:   PC_Composite     *jac = (PC_Composite*)pc->data;
131:   PC_CompositeLink next = jac->head;

134:   if (!next) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
135:   PCApply(next->pc,x,y);
136:   while (next->next) {
137:     next = next->next;
138:     VecSet(jac->work1,0.0);  /* zero since some PC's may not set all entries in the result */
139:     PCApply(next->pc,x,jac->work1);
140:     VecAXPY(y,1.0,jac->work1);
141:   }
142:   return(0);
143: }

147: static PetscErrorCode PCApplyTranspose_Composite_Additive(PC pc,Vec x,Vec y)
148: {
149:   PetscErrorCode   ierr;
150:   PC_Composite     *jac = (PC_Composite*)pc->data;
151:   PC_CompositeLink next = jac->head;

154:   if (!next) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"No composite preconditioners supplied via PCCompositeAddPC() or -pc_composite_pcs");
155:   PCApplyTranspose(next->pc,x,y);
156:   while (next->next) {
157:     next = next->next;
158:     VecSet(jac->work1,0.0);  /* zero since some PC's may not set all entries in the result */
159:     PCApplyTranspose(next->pc,x,jac->work1);
160:     VecAXPY(y,1.0,jac->work1);
161:   }
162:   return(0);
163: }

167: static PetscErrorCode PCSetUp_Composite(PC pc)
168: {
169:   PetscErrorCode   ierr;
170:   PC_Composite     *jac = (PC_Composite*)pc->data;
171:   PC_CompositeLink next = jac->head;

174:   if (!jac->work1) {
175:    MatGetVecs(pc->pmat,&jac->work1,0);
176:   }
177:   while (next) {
178:     PCSetOperators(next->pc,pc->mat,pc->pmat,pc->flag);
179:     next = next->next;
180:   }
181:   return(0);
182: }

186: static PetscErrorCode PCReset_Composite(PC pc)
187: {
188:   PC_Composite     *jac = (PC_Composite*)pc->data;
189:   PetscErrorCode   ierr;
190:   PC_CompositeLink next = jac->head;

193:   while (next) {
194:     PCReset(next->pc);
195:     next = next->next;
196:   }
197:   VecDestroy(&jac->work1);
198:   VecDestroy(&jac->work2);
199:   return(0);
200: }

204: static PetscErrorCode PCDestroy_Composite(PC pc)
205: {
206:   PC_Composite     *jac = (PC_Composite*)pc->data;
207:   PetscErrorCode   ierr;
208:   PC_CompositeLink next = jac->head,next_tmp;

211:   PCReset_Composite(pc);
212:   while (next) {
213:     PCDestroy(&next->pc);
214:     next_tmp = next;
215:     next     = next->next;
216:     PetscFree(next_tmp);
217:   }
218:   PetscFree(pc->data);
219:   return(0);
220: }

224: static PetscErrorCode PCSetFromOptions_Composite(PC pc)
225: {
226:   PC_Composite     *jac = (PC_Composite*)pc->data;
227:   PetscErrorCode   ierr;
228:   PetscInt         nmax = 8,i;
229:   PC_CompositeLink next;
230:   char             *pcs[8];
231:   PetscBool        flg;

234:   PetscOptionsHead("Composite preconditioner options");
235:     PetscOptionsEnum("-pc_composite_type","Type of composition","PCCompositeSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);
236:     if (flg) {
237:       PCCompositeSetType(pc,jac->type);
238:     }
239:     flg  = PETSC_FALSE;
240:     PetscOptionsBool("-pc_composite_true","Use true matrix for inner solves","PCCompositeSetUseTrue",flg,&flg,PETSC_NULL);
241:     if (flg) {
242:       PCCompositeSetUseTrue(pc);
243:     }
244:     PetscOptionsStringArray("-pc_composite_pcs","List of composite solvers","PCCompositeAddPC",pcs,&nmax,&flg);
245:     if (flg) {
246:       for (i=0; i<nmax; i++) {
247:         PCCompositeAddPC(pc,pcs[i]);
248:         PetscFree(pcs[i]); /* deallocate string pcs[i], which is allocated in PetscOptionsStringArray() */
249:       }
250:     }
251:   PetscOptionsTail();

253:   next = jac->head;
254:   while (next) {
255:     PCSetFromOptions(next->pc);
256:     next = next->next;
257:   }
258:   return(0);
259: }

263: static PetscErrorCode PCView_Composite(PC pc,PetscViewer viewer)
264: {
265:   PC_Composite     *jac = (PC_Composite*)pc->data;
266:   PetscErrorCode   ierr;
267:   PC_CompositeLink next = jac->head;
268:   PetscBool        iascii;

271:   PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
272:   if (iascii) {
273:     PetscViewerASCIIPrintf(viewer,"Composite PC type - %s\n",PCCompositeTypes[jac->type]);
274:     PetscViewerASCIIPrintf(viewer,"PCs on composite preconditioner follow\n");
275:     PetscViewerASCIIPrintf(viewer,"---------------------------------\n");
276:   } else {
277:     SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCComposite",((PetscObject)viewer)->type_name);
278:   }
279:   if (iascii) {
280:     PetscViewerASCIIPushTab(viewer);
281:   }
282:   while (next) {
283:     PCView(next->pc,viewer);
284:     next = next->next;
285:   }
286:   if (iascii) {
287:     PetscViewerASCIIPopTab(viewer);
288:     PetscViewerASCIIPrintf(viewer,"---------------------------------\n");
289:   }
290:   return(0);
291: }

293: /* ------------------------------------------------------------------------------*/

298: PetscErrorCode  PCCompositeSpecialSetAlpha_Composite(PC pc,PetscScalar alpha)
299: {
300:   PC_Composite *jac = (PC_Composite*)pc->data;
302:   jac->alpha = alpha;
303:   return(0);
304: }

310: PetscErrorCode  PCCompositeSetType_Composite(PC pc,PCCompositeType type)
311: {
313:   if (type == PC_COMPOSITE_ADDITIVE) {
314:     pc->ops->apply          = PCApply_Composite_Additive;
315:     pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
316:   } else if (type ==  PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
317:     pc->ops->apply          = PCApply_Composite_Multiplicative;
318:     pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative;
319:   } else if (type ==  PC_COMPOSITE_SPECIAL) {
320:     pc->ops->apply          = PCApply_Composite_Special;
321:     pc->ops->applytranspose = PETSC_NULL;
322:   } else SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG,"Unkown composite preconditioner type");
323:   return(0);
324: }

330: PetscErrorCode  PCCompositeAddPC_Composite(PC pc,PCType type)
331: {
332:   PC_Composite     *jac;
333:   PC_CompositeLink next,ilink;
334:   PetscErrorCode   ierr;
335:   PetscInt         cnt = 0;
336:   const char       *prefix;
337:   char             newprefix[8];

340:   PetscNewLog(pc,struct _PC_CompositeLink,&ilink);
341:   ilink->next = 0;
342:   PCCreate(((PetscObject)pc)->comm,&ilink->pc);
343:   PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->pc);

345:   jac  = (PC_Composite*)pc->data;
346:   next = jac->head;
347:   if (!next) {
348:     jac->head       = ilink;
349:     ilink->previous = PETSC_NULL;
350:   } else {
351:     cnt++;
352:     while (next->next) {
353:       next = next->next;
354:       cnt++;
355:     }
356:     next->next      = ilink;
357:     ilink->previous = next;
358:   }
359:   PCGetOptionsPrefix(pc,&prefix);
360:   PCSetOptionsPrefix(ilink->pc,prefix);
361:   sprintf(newprefix,"sub_%d_",(int)cnt);
362:   PCAppendOptionsPrefix(ilink->pc,newprefix);
363:   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
364:   PCSetType(ilink->pc,type);
365:   return(0);
366: }

372: PetscErrorCode  PCCompositeGetPC_Composite(PC pc,PetscInt n,PC *subpc)
373: {
374:   PC_Composite     *jac;
375:   PC_CompositeLink next;
376:   PetscInt         i;

379:   jac  = (PC_Composite*)pc->data;
380:   next = jac->head;
381:   for (i=0; i<n; i++) {
382:     if (!next->next) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_INCOMP,"Not enough PCs in composite preconditioner");
383:     next = next->next;
384:   }
385:   *subpc = next->pc;
386:   return(0);
387: }

393: PetscErrorCode  PCCompositeSetUseTrue_Composite(PC pc)
394: {
395:   PC_Composite   *jac;

398:   jac                  = (PC_Composite*)pc->data;
399:   jac->use_true_matrix = PETSC_TRUE;
400:   return(0);
401: }

404: /* -------------------------------------------------------------------------------- */
407: /*@
408:    PCCompositeSetType - Sets the type of composite preconditioner.
409:    
410:    Logically Collective on PC

412:    Input Parameter:
413: +  pc - the preconditioner context
414: -  type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL

416:    Options Database Key:
417: .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type

419:    Level: Developer

421: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
422: @*/
423: PetscErrorCode  PCCompositeSetType(PC pc,PCCompositeType type)
424: {

430:   PetscTryMethod(pc,"PCCompositeSetType_C",(PC,PCCompositeType),(pc,type));
431:   return(0);
432: }

436: /*@
437:    PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner
438:      for alphaI + R + S
439:    
440:    Logically Collective on PC

442:    Input Parameter:
443: +  pc - the preconditioner context
444: -  alpha - scale on identity

446:    Level: Developer

448: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
449: @*/
450: PetscErrorCode  PCCompositeSpecialSetAlpha(PC pc,PetscScalar alpha)
451: {

457:   PetscTryMethod(pc,"PCCompositeSpecialSetAlpha_C",(PC,PetscScalar),(pc,alpha));
458:   return(0);
459: }

463: /*@C
464:    PCCompositeAddPC - Adds another PC to the composite PC.
465:    
466:    Collective on PC

468:    Input Parameters:
469: +  pc - the preconditioner context
470: -  type - the type of the new preconditioner

472:    Level: Developer

474: .keywords: PC, composite preconditioner, add
475: @*/
476: PetscErrorCode  PCCompositeAddPC(PC pc,PCType type)
477: {

482:   PetscTryMethod(pc,"PCCompositeAddPC_C",(PC,PCType),(pc,type));
483:   return(0);
484: }

488: /*@
489:    PCCompositeGetPC - Gets one of the PC objects in the composite PC.
490:    
491:    Not Collective

493:    Input Parameter:
494: +  pc - the preconditioner context
495: -  n - the number of the pc requested

497:    Output Parameters:
498: .  subpc - the PC requested

500:    Level: Developer

502: .keywords: PC, get, composite preconditioner, sub preconditioner

504: .seealso: PCCompositeAddPC()
505: @*/
506: PetscErrorCode  PCCompositeGetPC(PC pc,PetscInt n,PC *subpc)
507: {

513:   PetscUseMethod(pc,"PCCompositeGetPC_C",(PC,PetscInt,PC *),(pc,n,subpc));
514:   return(0);
515: }

519: /*@
520:    PCCompositeSetUseTrue - Sets a flag to indicate that the true matrix (rather than
521:                       the matrix used to define the preconditioner) is used to compute
522:                       the residual when the multiplicative scheme is used.

524:    Logically Collective on PC

526:    Input Parameters:
527: .  pc - the preconditioner context

529:    Options Database Key:
530: .  -pc_composite_true - Activates PCCompositeSetUseTrue()

532:    Note:
533:    For the common case in which the preconditioning and linear 
534:    system matrices are identical, this routine is unnecessary.

536:    Level: Developer

538: .keywords: PC, composite preconditioner, set, true, flag

540: .seealso: PCSetOperators(), PCBJacobiSetUseTrueLocal(), PCKSPSetUseTrue()
541: @*/
542: PetscErrorCode  PCCompositeSetUseTrue(PC pc)
543: {

548:   PetscTryMethod(pc,"PCCompositeSetUseTrue_C",(PC),(pc));
549:   return(0);
550: }

552: /* -------------------------------------------------------------------------------------------*/

554: /*MC
555:      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners 

557:    Options Database Keys:
558: +  -pc_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
559: .  -pc_composite_true - Activates PCCompositeSetUseTrue()
560: -  -pc_composite_pcs - <pc0,pc1,...> list of PCs to compose

562:    Level: intermediate

564:    Concepts: composing solvers

566:    Notes: To use a Krylov method inside the composite preconditioner, set the PCType of one or more
567:           inner PCs to be PCKSP. 
568:           Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
569:           the incorrect answer) unless you use KSPFGMRES as the outer Krylov method


572: .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
573:            PCSHELL, PCKSP, PCCompositeSetType(), PCCompositeSpecialSetAlpha(), PCCompositeAddPC(),
574:            PCCompositeGetPC(), PCCompositeSetUseTrue()

576: M*/

581: PetscErrorCode  PCCreate_Composite(PC pc)
582: {
584:   PC_Composite   *jac;

587:   PetscNewLog(pc,PC_Composite,&jac);
588:   pc->ops->apply              = PCApply_Composite_Additive;
589:   pc->ops->applytranspose     = PCApplyTranspose_Composite_Additive;
590:   pc->ops->setup              = PCSetUp_Composite;
591:   pc->ops->reset              = PCReset_Composite;
592:   pc->ops->destroy            = PCDestroy_Composite;
593:   pc->ops->setfromoptions     = PCSetFromOptions_Composite;
594:   pc->ops->view               = PCView_Composite;
595:   pc->ops->applyrichardson    = 0;

597:   pc->data               = (void*)jac;
598:   jac->type              = PC_COMPOSITE_ADDITIVE;
599:   jac->work1             = 0;
600:   jac->work2             = 0;
601:   jac->head              = 0;

603:   PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSetType_C","PCCompositeSetType_Composite",
604:                     PCCompositeSetType_Composite);
605:   PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeAddPC_C","PCCompositeAddPC_Composite",
606:                     PCCompositeAddPC_Composite);
607:   PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeGetPC_C","PCCompositeGetPC_Composite",
608:                     PCCompositeGetPC_Composite);
609:   PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSetUseTrue_C","PCCompositeSetUseTrue_Composite",
610:                     PCCompositeSetUseTrue_Composite);
611:   PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCCompositeSpecialSetAlpha_C","PCCompositeSpecialSetAlpha_Composite",
612:                     PCCompositeSpecialSetAlpha_Composite);

614:   return(0);
615: }