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:   Mat              alpha_mat;
 21: } PC_Composite;

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

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

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

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

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

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

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

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

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

116:   PetscCall(PCApply(next->pc, x, jac->work1));
117:   if (jac->alpha_mat) {
118:     if (!jac->work2) PetscCall(VecDuplicate(jac->work1, &jac->work2));
119:     PetscCall(MatMult(jac->alpha_mat, jac->work1, jac->work2));
120:     PetscCall(PCApply(next->next->pc, jac->work2, y));
121:   } else PetscCall(PCApply(next->next->pc, jac->work1, y));
122:   PetscFunctionReturn(PETSC_SUCCESS);
123: }

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

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

133:   /* Set the reuse flag on children PCs */
134:   while (next) {
135:     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
136:     next = next->next;
137:   }
138:   next = jac->head;

140:   PetscCall(PCApply(next->pc, x, y));
141:   while (next->next) {
142:     next = next->next;
143:     PetscCall(PCApply(next->pc, x, jac->work1));
144:     PetscCall(VecAXPY(y, 1.0, jac->work1));
145:   }
146:   PetscFunctionReturn(PETSC_SUCCESS);
147: }

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

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

165: static PetscErrorCode PCSetUp_Composite(PC pc)
166: {
167:   PC_Composite    *jac  = (PC_Composite *)pc->data;
168:   PC_CompositeLink next = jac->head;
169:   DM               dm;

171:   PetscFunctionBegin;
172:   if (!jac->work1) PetscCall(MatCreateVecs(pc->pmat, &jac->work1, NULL));
173:   PetscCall(PCGetDM(pc, &dm));
174:   while (next) {
175:     if (!next->pc->dm) PetscCall(PCSetDM(next->pc, dm));
176:     if (!next->pc->mat) PetscCall(PCSetOperators(next->pc, pc->mat, pc->pmat));
177:     next = next->next;
178:   }
179:   PetscFunctionReturn(PETSC_SUCCESS);
180: }

182: static PetscErrorCode PCSetUpOnBlocks_Composite(PC pc)
183: {
184:   PC_Composite    *jac  = (PC_Composite *)pc->data;
185:   PC_CompositeLink next = jac->head;
186:   PCFailedReason   reason;

188:   PetscFunctionBegin;
189:   while (next) {
190:     PetscCall(PCSetUp(next->pc));
191:     PetscCall(PCGetFailedReason(next->pc, &reason));
192:     if (reason) pc->failedreason = reason;
193:     next = next->next;
194:   }
195:   PetscFunctionReturn(PETSC_SUCCESS);
196: }

198: static PetscErrorCode PCReset_Composite(PC pc)
199: {
200:   PC_Composite    *jac  = (PC_Composite *)pc->data;
201:   PC_CompositeLink next = jac->head;

203:   PetscFunctionBegin;
204:   while (next) {
205:     PetscCall(PCReset(next->pc));
206:     next = next->next;
207:   }
208:   PetscCall(VecDestroy(&jac->work1));
209:   PetscCall(VecDestroy(&jac->work2));
210:   PetscCall(MatDestroy(&jac->alpha_mat));
211:   PetscFunctionReturn(PETSC_SUCCESS);
212: }

214: static PetscErrorCode PCDestroy_Composite(PC pc)
215: {
216:   PC_Composite    *jac  = (PC_Composite *)pc->data;
217:   PC_CompositeLink next = jac->head, next_tmp;

219:   PetscFunctionBegin;
220:   PetscCall(PCReset_Composite(pc));
221:   while (next) {
222:     PetscCall(PCDestroy(&next->pc));
223:     next_tmp = next;
224:     next     = next->next;
225:     PetscCall(PetscFree(next_tmp));
226:   }
227:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", NULL));
228:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", NULL));
229:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", NULL));
230:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", NULL));
231:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", NULL));
232:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", NULL));
233:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", NULL));
234:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlphaMat_C", NULL));
235:   PetscCall(PetscFree(pc->data));
236:   PetscFunctionReturn(PETSC_SUCCESS);
237: }

239: static PetscErrorCode PCSetFromOptions_Composite(PC pc, PetscOptionItems *PetscOptionsObject)
240: {
241:   PC_Composite    *jac = (PC_Composite *)pc->data;
242:   PetscInt         nmax, i;
243:   PC_CompositeLink next;
244:   char            *pcs[1024];
245:   PetscBool        flg;

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

261:   next = jac->head;
262:   while (next) {
263:     PetscCall(PCSetFromOptions(next->pc));
264:     next = next->next;
265:   }
266:   PetscFunctionReturn(PETSC_SUCCESS);
267: }

269: static PetscErrorCode PCView_Composite(PC pc, PetscViewer viewer)
270: {
271:   PC_Composite    *jac  = (PC_Composite *)pc->data;
272:   PC_CompositeLink next = jac->head;
273:   PetscBool        iascii;

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

294: static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc, PetscScalar alpha)
295: {
296:   PC_Composite *jac = (PC_Composite *)pc->data;

298:   PetscFunctionBegin;
299:   jac->alpha = alpha;
300:   PetscFunctionReturn(PETSC_SUCCESS);
301: }

303: static PetscErrorCode PCCompositeSpecialSetAlphaMat_Composite(PC pc, Mat alpha_mat)
304: {
305:   PC_Composite *jac = (PC_Composite *)pc->data;

307:   PetscFunctionBegin;
308:   if (alpha_mat) {
310:     PetscCall(PetscObjectReference((PetscObject)alpha_mat));
311:   }
312:   PetscCall(MatDestroy(&jac->alpha_mat));
313:   jac->alpha_mat = alpha_mat;
314:   PetscFunctionReturn(PETSC_SUCCESS);
315: }

317: static PetscErrorCode PCCompositeSetType_Composite(PC pc, PCCompositeType type)
318: {
319:   PC_Composite *jac = (PC_Composite *)pc->data;

321:   PetscFunctionBegin;
322:   if (type == PC_COMPOSITE_ADDITIVE) {
323:     pc->ops->apply          = PCApply_Composite_Additive;
324:     pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
325:   } else if (type == PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
326:     pc->ops->apply          = PCApply_Composite_Multiplicative;
327:     pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative;
328:   } else if (type == PC_COMPOSITE_SPECIAL) {
329:     pc->ops->apply          = PCApply_Composite_Special;
330:     pc->ops->applytranspose = NULL;
331:   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Unknown composite preconditioner type");
332:   jac->type = type;
333:   PetscFunctionReturn(PETSC_SUCCESS);
334: }

336: static PetscErrorCode PCCompositeGetType_Composite(PC pc, PCCompositeType *type)
337: {
338:   PC_Composite *jac = (PC_Composite *)pc->data;

340:   PetscFunctionBegin;
341:   *type = jac->type;
342:   PetscFunctionReturn(PETSC_SUCCESS);
343: }

345: static PetscErrorCode PCCompositeAddPC_Composite(PC pc, PC subpc)
346: {
347:   PC_Composite    *jac;
348:   PC_CompositeLink next, ilink;
349:   PetscInt         cnt = 0;
350:   const char      *prefix;
351:   char             newprefix[20];

353:   PetscFunctionBegin;
354:   PetscCall(PetscNew(&ilink));
355:   ilink->next = NULL;
356:   ilink->pc   = subpc;

358:   jac  = (PC_Composite *)pc->data;
359:   next = jac->head;
360:   if (!next) {
361:     jac->head       = ilink;
362:     ilink->previous = NULL;
363:   } else {
364:     cnt++;
365:     while (next->next) {
366:       next = next->next;
367:       cnt++;
368:     }
369:     next->next      = ilink;
370:     ilink->previous = next;
371:   }
372:   PetscCall(PCGetOptionsPrefix(pc, &prefix));
373:   PetscCall(PCSetOptionsPrefix(subpc, prefix));
374:   PetscCall(PetscSNPrintf(newprefix, 20, "sub_%" PetscInt_FMT "_", cnt));
375:   PetscCall(PCAppendOptionsPrefix(subpc, newprefix));
376:   PetscCall(PetscObjectReference((PetscObject)subpc));
377:   PetscFunctionReturn(PETSC_SUCCESS);
378: }

380: static PetscErrorCode PCCompositeAddPCType_Composite(PC pc, PCType type)
381: {
382:   PC subpc;

384:   PetscFunctionBegin;
385:   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &subpc));
386:   PetscCall(PetscObjectIncrementTabLevel((PetscObject)subpc, (PetscObject)pc, 1));
387:   PetscCall(PCCompositeAddPC_Composite(pc, subpc));
388:   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
389:   PetscCall(PCSetType(subpc, type));
390:   PetscCall(PCDestroy(&subpc));
391:   PetscFunctionReturn(PETSC_SUCCESS);
392: }

394: static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc, PetscInt *n)
395: {
396:   PC_Composite    *jac;
397:   PC_CompositeLink next;

399:   PetscFunctionBegin;
400:   jac  = (PC_Composite *)pc->data;
401:   next = jac->head;
402:   *n   = 0;
403:   while (next) {
404:     next = next->next;
405:     (*n)++;
406:   }
407:   PetscFunctionReturn(PETSC_SUCCESS);
408: }

410: static PetscErrorCode PCCompositeGetPC_Composite(PC pc, PetscInt n, PC *subpc)
411: {
412:   PC_Composite    *jac;
413:   PC_CompositeLink next;
414:   PetscInt         i;

416:   PetscFunctionBegin;
417:   jac  = (PC_Composite *)pc->data;
418:   next = jac->head;
419:   for (i = 0; i < n; i++) {
420:     PetscCheck(next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Not enough PCs in composite preconditioner");
421:     next = next->next;
422:   }
423:   *subpc = next->pc;
424:   PetscFunctionReturn(PETSC_SUCCESS);
425: }

427: /*@
428:   PCCompositeSetType - Sets the type of composite preconditioner.

430:   Logically Collective

432:   Input Parameters:
433: + pc   - the preconditioner context
434: - type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`

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

439:   Level: advanced

441: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
442:           `PCCompositeGetType()`
443: @*/
444: PetscErrorCode PCCompositeSetType(PC pc, PCCompositeType type)
445: {
446:   PetscFunctionBegin;
449:   PetscTryMethod(pc, "PCCompositeSetType_C", (PC, PCCompositeType), (pc, type));
450:   PetscFunctionReturn(PETSC_SUCCESS);
451: }

453: /*@
454:   PCCompositeGetType - Gets the type of composite preconditioner.

456:   Logically Collective

458:   Input Parameter:
459: . pc - the preconditioner context

461:   Output Parameter:
462: . type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`

464:   Level: advanced

466: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
467:           `PCCompositeSetType()`
468: @*/
469: PetscErrorCode PCCompositeGetType(PC pc, PCCompositeType *type)
470: {
471:   PetscFunctionBegin;
473:   PetscUseMethod(pc, "PCCompositeGetType_C", (PC, PCCompositeType *), (pc, type));
474:   PetscFunctionReturn(PETSC_SUCCESS);
475: }

477: /*@
478:   PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner, `PC_COMPOSITE_SPECIAL`,
479:   for $\alpha I + R + S$

481:   Logically Collective

483:   Input Parameters:
484: + pc    - the preconditioner context
485: - alpha - scale on identity

487:   Level: developer

489: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
490:           `PCCompositeSetType()`, `PCCompositeGetType()`
491: @*/
492: PetscErrorCode PCCompositeSpecialSetAlpha(PC pc, PetscScalar alpha)
493: {
494:   PetscFunctionBegin;
497:   PetscTryMethod(pc, "PCCompositeSpecialSetAlpha_C", (PC, PetscScalar), (pc, alpha));
498:   PetscFunctionReturn(PETSC_SUCCESS);
499: }

501: PetscErrorCode PCCompositeSpecialSetAlphaMat(PC pc, Mat alpha_mat)
502: {
503:   PetscFunctionBegin;
505:   PetscTryMethod(pc, "PCCompositeSpecialSetAlphaMat_C", (PC, Mat), (pc, alpha_mat));
506:   PetscFunctionReturn(PETSC_SUCCESS);
507: }

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

512:   Collective

514:   Input Parameters:
515: + pc   - the preconditioner context
516: - type - the type of the new preconditioner

518:   Level: intermediate

520: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
521: @*/
522: PetscErrorCode PCCompositeAddPCType(PC pc, PCType type)
523: {
524:   PetscFunctionBegin;
526:   PetscTryMethod(pc, "PCCompositeAddPCType_C", (PC, PCType), (pc, type));
527:   PetscFunctionReturn(PETSC_SUCCESS);
528: }

530: /*@
531:   PCCompositeAddPC - Adds another `PC` to the composite `PC`.

533:   Collective

535:   Input Parameters:
536: + pc    - the preconditioner context
537: - subpc - the new preconditioner

539:   Level: intermediate

541: .seealso: [](ch_ksp), `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`
542: @*/
543: PetscErrorCode PCCompositeAddPC(PC pc, PC subpc)
544: {
545:   PetscFunctionBegin;
548:   PetscTryMethod(pc, "PCCompositeAddPC_C", (PC, PC), (pc, subpc));
549:   PetscFunctionReturn(PETSC_SUCCESS);
550: }

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

555:   Not Collective

557:   Input Parameter:
558: . pc - the preconditioner context

560:   Output Parameter:
561: . num - the number of sub pcs

563:   Level: developer

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

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

579:   Not Collective

581:   Input Parameters:
582: + pc - the preconditioner context
583: - n  - the number of the pc requested

585:   Output Parameter:
586: . subpc - the PC requested

588:   Level: intermediate

590:   Note:
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), `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`, `PCSetOperators()`
595: @*/
596: PetscErrorCode PCCompositeGetPC(PC pc, PetscInt n, PC *subpc)
597: {
598:   PetscFunctionBegin;
600:   PetscAssertPointer(subpc, 3);
601:   PetscUseMethod(pc, "PCCompositeGetPC_C", (PC, PetscInt, PC *), (pc, n, subpc));
602:   PetscFunctionReturn(PETSC_SUCCESS);
603: }

605: /*MC
606:      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners

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

613:    Level: intermediate

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

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

623: .seealso: [](ch_ksp), `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
624:           `PCSHELL`, `PCKSP`, `PCCompositeSetType()`, `PCCompositeSpecialSetAlpha()`, `PCCompositeAddPCType()`,
625:           `PCCompositeGetPC()`, `PCSetUseAmat()`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
626: M*/

628: PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc)
629: {
630:   PC_Composite *jac;

632:   PetscFunctionBegin;
633:   PetscCall(PetscNew(&jac));

635:   pc->ops->apply           = PCApply_Composite_Additive;
636:   pc->ops->applytranspose  = PCApplyTranspose_Composite_Additive;
637:   pc->ops->setup           = PCSetUp_Composite;
638:   pc->ops->setuponblocks   = PCSetUpOnBlocks_Composite;
639:   pc->ops->reset           = PCReset_Composite;
640:   pc->ops->destroy         = PCDestroy_Composite;
641:   pc->ops->setfromoptions  = PCSetFromOptions_Composite;
642:   pc->ops->view            = PCView_Composite;
643:   pc->ops->applyrichardson = NULL;

645:   pc->data       = (void *)jac;
646:   jac->type      = PC_COMPOSITE_ADDITIVE;
647:   jac->work1     = NULL;
648:   jac->work2     = NULL;
649:   jac->head      = NULL;
650:   jac->alpha_mat = NULL;

652:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", PCCompositeSetType_Composite));
653:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", PCCompositeGetType_Composite));
654:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", PCCompositeAddPCType_Composite));
655:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", PCCompositeAddPC_Composite));
656:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", PCCompositeGetNumberPC_Composite));
657:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", PCCompositeGetPC_Composite));
658:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", PCCompositeSpecialSetAlpha_Composite));
659:   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlphaMat_C", PCCompositeSpecialSetAlphaMat_Composite));
660:   PetscFunctionReturn(PETSC_SUCCESS);
661: }