Actual source code: composite.c

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

  7: typedef struct _PC_CompositeLink *PC_CompositeLink;
  8: struct _PC_CompositeLink {
  9:   PC               pc;
 10:   PC_CompositeLink next;
 11:   PC_CompositeLink previous;
 12: };

 14: typedef struct {
 15:   PC_CompositeLink head;
 16:   PCCompositeType  type;
 17:   Vec              work1;
 18:   Vec              work2;
 19:   PetscScalar      alpha;
 20: } PC_Composite;

 22: static PetscErrorCode PCApply_Composite_Multiplicative(PC pc, Vec x, Vec y)
 23: {
 24:   PC_Composite    *jac  = (PC_Composite *)pc->data;
 25:   PC_CompositeLink next = jac->head;
 26:   Mat              mat  = pc->pmat;

 28:   PetscFunctionBegin;
 29:   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");

 31:   /* Set the reuse flag on children PCs */
 32:   while (next) {
 33:     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
 34:     next = next->next;
 35:   }
 36:   next = jac->head;

 38:   if (next->next && !jac->work2) { /* allocate second work vector */
 39:     PetscCall(VecDuplicate(jac->work1, &jac->work2));
 40:   }
 41:   if (pc->useAmat) mat = pc->mat;
 42:   PetscCall(PCApply(next->pc, x, y)); /* y <- B x */
 43:   while (next->next) {
 44:     next = next->next;
 45:     PetscCall(MatMult(mat, y, jac->work1));               /* work1 <- A y */
 46:     PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x)); /* work2 <- x - work1 */
 47:     PetscCall(PCApply(next->pc, jac->work2, jac->work1)); /* work1 <- C work2 */
 48:     PetscCall(VecAXPY(y, 1.0, jac->work1));               /* y <- y + work1 = B x + C (x - A B x) = (B + C (1 - A B)) x */
 49:   }
 50:   if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
 51:     while (next->previous) {
 52:       next = next->previous;
 53:       PetscCall(MatMult(mat, y, jac->work1));
 54:       PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
 55:       PetscCall(PCApply(next->pc, jac->work2, jac->work1));
 56:       PetscCall(VecAXPY(y, 1.0, jac->work1));
 57:     }
 58:   }
 59:   PetscFunctionReturn(PETSC_SUCCESS);
 60: }

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

 68:   PetscFunctionBegin;
 69:   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
 70:   if (next->next && !jac->work2) { /* allocate second work vector */
 71:     PetscCall(VecDuplicate(jac->work1, &jac->work2));
 72:   }
 73:   if (pc->useAmat) mat = pc->mat;
 74:   /* locate last PC */
 75:   while (next->next) next = next->next;
 76:   PetscCall(PCApplyTranspose(next->pc, x, y));
 77:   while (next->previous) {
 78:     next = next->previous;
 79:     PetscCall(MatMultTranspose(mat, y, jac->work1));
 80:     PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
 81:     PetscCall(PCApplyTranspose(next->pc, jac->work2, jac->work1));
 82:     PetscCall(VecAXPY(y, 1.0, jac->work1));
 83:   }
 84:   if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
 85:     next = jac->head;
 86:     while (next->next) {
 87:       next = next->next;
 88:       PetscCall(MatMultTranspose(mat, y, jac->work1));
 89:       PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
 90:       PetscCall(PCApplyTranspose(next->pc, jac->work2, jac->work1));
 91:       PetscCall(VecAXPY(y, 1.0, jac->work1));
 92:     }
 93:   }
 94:   PetscFunctionReturn(PETSC_SUCCESS);
 95: }

 97: /*
 98:     This is very special for a matrix of the form alpha I + R + S
 99:     where first preconditioner is built from alpha I + S and second from
100:     alpha I + R
101: */
102: static PetscErrorCode PCApply_Composite_Special(PC pc, Vec x, Vec y)
103: {
104:   PC_Composite    *jac  = (PC_Composite *)pc->data;
105:   PC_CompositeLink next = jac->head;

107:   PetscFunctionBegin;
108:   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
109:   PetscCheck(next->next && !next->next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Special composite preconditioners requires exactly two PCs");

111:   /* Set the reuse flag on children PCs */
112:   PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
113:   PetscCall(PCSetReusePreconditioner(next->next->pc, pc->reusepreconditioner));

115:   PetscCall(PCApply(next->pc, x, jac->work1));
116:   PetscCall(PCApply(next->next->pc, jac->work1, y));
117:   PetscFunctionReturn(PETSC_SUCCESS);
118: }

120: static PetscErrorCode PCApply_Composite_Additive(PC pc, Vec x, Vec y)
121: {
122:   PC_Composite    *jac  = (PC_Composite *)pc->data;
123:   PC_CompositeLink next = jac->head;

125:   PetscFunctionBegin;
126:   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");

128:   /* Set the reuse flag on children PCs */
129:   while (next) {
130:     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
131:     next = next->next;
132:   }
133:   next = jac->head;

135:   PetscCall(PCApply(next->pc, x, y));
136:   while (next->next) {
137:     next = next->next;
138:     PetscCall(PCApply(next->pc, x, jac->work1));
139:     PetscCall(VecAXPY(y, 1.0, jac->work1));
140:   }
141:   PetscFunctionReturn(PETSC_SUCCESS);
142: }

144: static PetscErrorCode PCApplyTranspose_Composite_Additive(PC pc, Vec x, Vec y)
145: {
146:   PC_Composite    *jac  = (PC_Composite *)pc->data;
147:   PC_CompositeLink next = jac->head;

149:   PetscFunctionBegin;
150:   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
151:   PetscCall(PCApplyTranspose(next->pc, x, y));
152:   while (next->next) {
153:     next = next->next;
154:     PetscCall(PCApplyTranspose(next->pc, x, jac->work1));
155:     PetscCall(VecAXPY(y, 1.0, jac->work1));
156:   }
157:   PetscFunctionReturn(PETSC_SUCCESS);
158: }

160: static PetscErrorCode PCSetUp_Composite(PC pc)
161: {
162:   PC_Composite    *jac  = (PC_Composite *)pc->data;
163:   PC_CompositeLink next = jac->head;
164:   DM               dm;

166:   PetscFunctionBegin;
167:   if (!jac->work1) PetscCall(MatCreateVecs(pc->pmat, &jac->work1, NULL));
168:   PetscCall(PCGetDM(pc, &dm));
169:   while (next) {
170:     if (!next->pc->dm) PetscCall(PCSetDM(next->pc, dm));
171:     if (!next->pc->mat) PetscCall(PCSetOperators(next->pc, pc->mat, pc->pmat));
172:     next = next->next;
173:   }
174:   PetscFunctionReturn(PETSC_SUCCESS);
175: }

177: static PetscErrorCode PCSetUpOnBlocks_Composite(PC pc)
178: {
179:   PC_Composite    *jac  = (PC_Composite *)pc->data;
180:   PC_CompositeLink next = jac->head;
181:   PCFailedReason   reason;

183:   PetscFunctionBegin;
184:   while (next) {
185:     PetscCall(PCSetUp(next->pc));
186:     PetscCall(PCGetFailedReasonRank(next->pc, &reason));
187:     if (reason) pc->failedreason = reason;
188:     next = next->next;
189:   }
190:   PetscFunctionReturn(PETSC_SUCCESS);
191: }

193: static PetscErrorCode PCReset_Composite(PC pc)
194: {
195:   PC_Composite    *jac  = (PC_Composite *)pc->data;
196:   PC_CompositeLink next = jac->head;

198:   PetscFunctionBegin;
199:   while (next) {
200:     PetscCall(PCReset(next->pc));
201:     next = next->next;
202:   }
203:   PetscCall(VecDestroy(&jac->work1));
204:   PetscCall(VecDestroy(&jac->work2));
205:   PetscFunctionReturn(PETSC_SUCCESS);
206: }

208: static PetscErrorCode PCDestroy_Composite(PC pc)
209: {
210:   PC_Composite    *jac  = (PC_Composite *)pc->data;
211:   PC_CompositeLink next = jac->head, next_tmp;

213:   PetscFunctionBegin;
214:   PetscCall(PCReset_Composite(pc));
215:   while (next) {
216:     PetscCall(PCDestroy(&next->pc));
217:     next_tmp = next;
218:     next     = next->next;
219:     PetscCall(PetscFree(next_tmp));
220:   }
221:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", NULL));
222:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", NULL));
223:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", NULL));
224:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", NULL));
225:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", NULL));
226:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", NULL));
227:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", NULL));
228:   PetscCall(PetscFree(pc->data));
229:   PetscFunctionReturn(PETSC_SUCCESS);
230: }

232: static PetscErrorCode PCSetFromOptions_Composite(PC pc, PetscOptionItems *PetscOptionsObject)
233: {
234:   PC_Composite    *jac = (PC_Composite *)pc->data;
235:   PetscInt         nmax, i;
236:   PC_CompositeLink next;
237:   char            *pcs[1024];
238:   PetscBool        flg;

240:   PetscFunctionBegin;
241:   PetscOptionsHeadBegin(PetscOptionsObject, "Composite preconditioner options");
242:   PetscCall(PetscOptionsEnum("-pc_composite_type", "Type of composition", "PCCompositeSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&jac->type, &flg));
243:   if (flg) PetscCall(PCCompositeSetType(pc, jac->type));
244:   nmax = (PetscInt)PETSC_STATIC_ARRAY_LENGTH(pcs);
245:   PetscCall(PetscOptionsStringArray("-pc_composite_pcs", "List of composite solvers", "PCCompositeAddPCType", pcs, &nmax, &flg));
246:   if (flg) {
247:     for (i = 0; i < nmax; i++) {
248:       PetscCall(PCCompositeAddPCType(pc, pcs[i]));
249:       PetscCall(PetscFree(pcs[i])); /* deallocate string pcs[i], which is allocated in PetscOptionsStringArray() */
250:     }
251:   }
252:   PetscOptionsHeadEnd();

254:   next = jac->head;
255:   while (next) {
256:     PetscCall(PCSetFromOptions(next->pc));
257:     next = next->next;
258:   }
259:   PetscFunctionReturn(PETSC_SUCCESS);
260: }

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

268:   PetscFunctionBegin;
269:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
270:   if (iascii) {
271:     PetscCall(PetscViewerASCIIPrintf(viewer, "Composite PC type - %s\n", PCCompositeTypes[jac->type]));
272:     PetscCall(PetscViewerASCIIPrintf(viewer, "PCs on composite preconditioner follow\n"));
273:     PetscCall(PetscViewerASCIIPrintf(viewer, "---------------------------------\n"));
274:   }
275:   if (iascii) PetscCall(PetscViewerASCIIPushTab(viewer));
276:   while (next) {
277:     PetscCall(PCView(next->pc, viewer));
278:     next = next->next;
279:   }
280:   if (iascii) {
281:     PetscCall(PetscViewerASCIIPopTab(viewer));
282:     PetscCall(PetscViewerASCIIPrintf(viewer, "---------------------------------\n"));
283:   }
284:   PetscFunctionReturn(PETSC_SUCCESS);
285: }

287: static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc, PetscScalar alpha)
288: {
289:   PC_Composite *jac = (PC_Composite *)pc->data;

291:   PetscFunctionBegin;
292:   jac->alpha = alpha;
293:   PetscFunctionReturn(PETSC_SUCCESS);
294: }

296: static PetscErrorCode PCCompositeSetType_Composite(PC pc, PCCompositeType type)
297: {
298:   PC_Composite *jac = (PC_Composite *)pc->data;

300:   PetscFunctionBegin;
301:   if (type == PC_COMPOSITE_ADDITIVE) {
302:     pc->ops->apply          = PCApply_Composite_Additive;
303:     pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
304:   } else if (type == PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
305:     pc->ops->apply          = PCApply_Composite_Multiplicative;
306:     pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative;
307:   } else if (type == PC_COMPOSITE_SPECIAL) {
308:     pc->ops->apply          = PCApply_Composite_Special;
309:     pc->ops->applytranspose = NULL;
310:   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Unknown composite preconditioner type");
311:   jac->type = type;
312:   PetscFunctionReturn(PETSC_SUCCESS);
313: }

315: static PetscErrorCode PCCompositeGetType_Composite(PC pc, PCCompositeType *type)
316: {
317:   PC_Composite *jac = (PC_Composite *)pc->data;

319:   PetscFunctionBegin;
320:   *type = jac->type;
321:   PetscFunctionReturn(PETSC_SUCCESS);
322: }

324: static PetscErrorCode PCCompositeAddPC_Composite(PC pc, PC subpc)
325: {
326:   PC_Composite    *jac;
327:   PC_CompositeLink next, ilink;
328:   PetscInt         cnt = 0;
329:   const char      *prefix;
330:   char             newprefix[20];

332:   PetscFunctionBegin;
333:   PetscCall(PetscNew(&ilink));
334:   ilink->next = NULL;
335:   ilink->pc   = subpc;

337:   jac  = (PC_Composite *)pc->data;
338:   next = jac->head;
339:   if (!next) {
340:     jac->head       = ilink;
341:     ilink->previous = NULL;
342:   } else {
343:     cnt++;
344:     while (next->next) {
345:       next = next->next;
346:       cnt++;
347:     }
348:     next->next      = ilink;
349:     ilink->previous = next;
350:   }
351:   PetscCall(PCGetOptionsPrefix(pc, &prefix));
352:   PetscCall(PCSetOptionsPrefix(subpc, prefix));
353:   PetscCall(PetscSNPrintf(newprefix, 20, "sub_%d_", (int)cnt));
354:   PetscCall(PCAppendOptionsPrefix(subpc, newprefix));
355:   PetscCall(PetscObjectReference((PetscObject)subpc));
356:   PetscFunctionReturn(PETSC_SUCCESS);
357: }

359: static PetscErrorCode PCCompositeAddPCType_Composite(PC pc, PCType type)
360: {
361:   PC subpc;

363:   PetscFunctionBegin;
364:   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &subpc));
365:   PetscCall(PetscObjectIncrementTabLevel((PetscObject)subpc, (PetscObject)pc, 1));
366:   PetscCall(PCCompositeAddPC_Composite(pc, subpc));
367:   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
368:   PetscCall(PCSetType(subpc, type));
369:   PetscCall(PCDestroy(&subpc));
370:   PetscFunctionReturn(PETSC_SUCCESS);
371: }

373: static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc, PetscInt *n)
374: {
375:   PC_Composite    *jac;
376:   PC_CompositeLink next;

378:   PetscFunctionBegin;
379:   jac  = (PC_Composite *)pc->data;
380:   next = jac->head;
381:   *n   = 0;
382:   while (next) {
383:     next = next->next;
384:     (*n)++;
385:   }
386:   PetscFunctionReturn(PETSC_SUCCESS);
387: }

389: static PetscErrorCode PCCompositeGetPC_Composite(PC pc, PetscInt n, PC *subpc)
390: {
391:   PC_Composite    *jac;
392:   PC_CompositeLink next;
393:   PetscInt         i;

395:   PetscFunctionBegin;
396:   jac  = (PC_Composite *)pc->data;
397:   next = jac->head;
398:   for (i = 0; i < n; i++) {
399:     PetscCheck(next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Not enough PCs in composite preconditioner");
400:     next = next->next;
401:   }
402:   *subpc = next->pc;
403:   PetscFunctionReturn(PETSC_SUCCESS);
404: }

406: /*@
407:   PCCompositeSetType - Sets the type of composite preconditioner.

409:   Logically Collective

411:   Input Parameters:
412: + pc   - the preconditioner context
413: - type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`

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

418:   Level: advanced

420: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
421:           `PCCompositeGetType()`
422: @*/
423: PetscErrorCode PCCompositeSetType(PC pc, PCCompositeType type)
424: {
425:   PetscFunctionBegin;
428:   PetscTryMethod(pc, "PCCompositeSetType_C", (PC, PCCompositeType), (pc, type));
429:   PetscFunctionReturn(PETSC_SUCCESS);
430: }

432: /*@
433:   PCCompositeGetType - Gets the type of composite preconditioner.

435:   Logically Collective

437:   Input Parameter:
438: . pc - the preconditioner context

440:   Output Parameter:
441: . type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`

443:   Level: advanced

445: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
446:           `PCCompositeSetType()`
447: @*/
448: PetscErrorCode PCCompositeGetType(PC pc, PCCompositeType *type)
449: {
450:   PetscFunctionBegin;
452:   PetscUseMethod(pc, "PCCompositeGetType_C", (PC, PCCompositeType *), (pc, type));
453:   PetscFunctionReturn(PETSC_SUCCESS);
454: }

456: /*@
457:   PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner, `PC_COMPOSITE_SPECIAL`,
458:   for $\alpha I + R + S$

460:   Logically Collective

462:   Input Parameters:
463: + pc    - the preconditioner context
464: - alpha - scale on identity

466:   Level: developer

468: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
469:           `PCCompositeSetType()`, `PCCompositeGetType()`
470: @*/
471: PetscErrorCode PCCompositeSpecialSetAlpha(PC pc, PetscScalar alpha)
472: {
473:   PetscFunctionBegin;
476:   PetscTryMethod(pc, "PCCompositeSpecialSetAlpha_C", (PC, PetscScalar), (pc, alpha));
477:   PetscFunctionReturn(PETSC_SUCCESS);
478: }

480: /*@C
481:   PCCompositeAddPCType - Adds another `PC` of the given type to the composite `PC`.

483:   Collective

485:   Input Parameters:
486: + pc   - the preconditioner context
487: - type - the type of the new preconditioner

489:   Level: intermediate

491: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
492: @*/
493: PetscErrorCode PCCompositeAddPCType(PC pc, PCType type)
494: {
495:   PetscFunctionBegin;
497:   PetscTryMethod(pc, "PCCompositeAddPCType_C", (PC, PCType), (pc, type));
498:   PetscFunctionReturn(PETSC_SUCCESS);
499: }

501: /*@
502:   PCCompositeAddPC - Adds another `PC` to the composite `PC`.

504:   Collective

506:   Input Parameters:
507: + pc    - the preconditioner context
508: - subpc - the new preconditioner

510:   Level: intermediate

512: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`
513: @*/
514: PetscErrorCode PCCompositeAddPC(PC pc, PC subpc)
515: {
516:   PetscFunctionBegin;
519:   PetscTryMethod(pc, "PCCompositeAddPC_C", (PC, PC), (pc, subpc));
520:   PetscFunctionReturn(PETSC_SUCCESS);
521: }

523: /*@
524:   PCCompositeGetNumberPC - Gets the number of `PC` objects in the composite `PC`.

526:   Not Collective

528:   Input Parameter:
529: . pc - the preconditioner context

531:   Output Parameter:
532: . num - the number of sub pcs

534:   Level: developer

536: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PCCompositeGetPC()`, `PCCompositeAddPC()`, `PCCompositeAddPCType()`
537: @*/
538: PetscErrorCode PCCompositeGetNumberPC(PC pc, PetscInt *num)
539: {
540:   PetscFunctionBegin;
542:   PetscAssertPointer(num, 2);
543:   PetscUseMethod(pc, "PCCompositeGetNumberPC_C", (PC, PetscInt *), (pc, num));
544:   PetscFunctionReturn(PETSC_SUCCESS);
545: }

547: /*@
548:   PCCompositeGetPC - Gets one of the `PC` objects in the composite `PC`.

550:   Not Collective

552:   Input Parameters:
553: + pc - the preconditioner context
554: - n  - the number of the pc requested

556:   Output Parameter:
557: . subpc - the PC requested

559:   Level: intermediate

561:   Note:
562:   To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
563:   call `PCSetOperators()` on that `PC`.

565: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`, `PCSetOperators()`
566: @*/
567: PetscErrorCode PCCompositeGetPC(PC pc, PetscInt n, PC *subpc)
568: {
569:   PetscFunctionBegin;
571:   PetscAssertPointer(subpc, 3);
572:   PetscUseMethod(pc, "PCCompositeGetPC_C", (PC, PetscInt, PC *), (pc, n, subpc));
573:   PetscFunctionReturn(PETSC_SUCCESS);
574: }

576: /*MC
577:      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners

579:    Options Database Keys:
580: +  -pc_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
581: .  -pc_use_amat                                                                                  - activates `PCSetUseAmat()`
582: -  -pc_composite_pcs                                                                             - <pc0,pc1,...> list of PCs to compose

584:    Level: intermediate

586:    Notes:
587:    To use a Krylov method inside the composite preconditioner, set the `PCType` of one or more
588:    inner `PC`s to be `PCKSP`. Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
589:    the incorrect answer) unless you use `KSPFGMRES` as the outer Krylov method

591:    To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
592:    call `PCSetOperators()` on that `PC`.

594: .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
595:           `PCSHELL`, `PCKSP`, `PCCompositeSetType()`, `PCCompositeSpecialSetAlpha()`, `PCCompositeAddPCType()`,
596:           `PCCompositeGetPC()`, `PCSetUseAmat()`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
597: M*/

599: PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc)
600: {
601:   PC_Composite *jac;

603:   PetscFunctionBegin;
604:   PetscCall(PetscNew(&jac));

606:   pc->ops->apply           = PCApply_Composite_Additive;
607:   pc->ops->applytranspose  = PCApplyTranspose_Composite_Additive;
608:   pc->ops->setup           = PCSetUp_Composite;
609:   pc->ops->setuponblocks   = PCSetUpOnBlocks_Composite;
610:   pc->ops->reset           = PCReset_Composite;
611:   pc->ops->destroy         = PCDestroy_Composite;
612:   pc->ops->setfromoptions  = PCSetFromOptions_Composite;
613:   pc->ops->view            = PCView_Composite;
614:   pc->ops->applyrichardson = NULL;

616:   pc->data   = (void *)jac;
617:   jac->type  = PC_COMPOSITE_ADDITIVE;
618:   jac->work1 = NULL;
619:   jac->work2 = NULL;
620:   jac->head  = NULL;

622:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", PCCompositeSetType_Composite));
623:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", PCCompositeGetType_Composite));
624:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", PCCompositeAddPCType_Composite));
625:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", PCCompositeAddPC_Composite));
626:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", PCCompositeGetNumberPC_Composite));
627:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", PCCompositeGetPC_Composite));
628:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", PCCompositeSpecialSetAlpha_Composite));
629:   PetscFunctionReturn(PETSC_SUCCESS);
630: }