xref: /petsc/src/ksp/pc/impls/composite/composite.c (revision e0f629dd96229b85b8d4fbf4a5ed4f197d232daa)
1 
2 /*
3       Defines a preconditioner that can consist of a collection of PCs
4 */
5 #include <petsc/private/pcimpl.h>
6 #include <petscksp.h> /*I "petscksp.h" I*/
7 
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 } PC_Composite;
22 
23 static PetscErrorCode PCApply_Composite_Multiplicative(PC pc, Vec x, Vec y) {
24   PC_Composite    *jac  = (PC_Composite *)pc->data;
25   PC_CompositeLink next = jac->head;
26   Mat              mat  = pc->pmat;
27 
28   PetscFunctionBegin;
29 
30   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
31 
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;
38 
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(0);
61 }
62 
63 static PetscErrorCode PCApplyTranspose_Composite_Multiplicative(PC pc, Vec x, Vec y) {
64   PC_Composite    *jac  = (PC_Composite *)pc->data;
65   PC_CompositeLink next = jac->head;
66   Mat              mat  = pc->pmat;
67 
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(0);
95 }
96 
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   PC_Composite    *jac  = (PC_Composite *)pc->data;
104   PC_CompositeLink next = jac->head;
105 
106   PetscFunctionBegin;
107   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
108   PetscCheck(next->next && !next->next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Special composite preconditioners requires exactly two PCs");
109 
110   /* Set the reuse flag on children PCs */
111   PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
112   PetscCall(PCSetReusePreconditioner(next->next->pc, pc->reusepreconditioner));
113 
114   PetscCall(PCApply(next->pc, x, jac->work1));
115   PetscCall(PCApply(next->next->pc, jac->work1, y));
116   PetscFunctionReturn(0);
117 }
118 
119 static PetscErrorCode PCApply_Composite_Additive(PC pc, Vec x, Vec y) {
120   PC_Composite    *jac  = (PC_Composite *)pc->data;
121   PC_CompositeLink next = jac->head;
122 
123   PetscFunctionBegin;
124   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
125 
126   /* Set the reuse flag on children PCs */
127   while (next) {
128     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
129     next = next->next;
130   }
131   next = jac->head;
132 
133   PetscCall(PCApply(next->pc, x, y));
134   while (next->next) {
135     next = next->next;
136     PetscCall(PCApply(next->pc, x, jac->work1));
137     PetscCall(VecAXPY(y, 1.0, jac->work1));
138   }
139   PetscFunctionReturn(0);
140 }
141 
142 static PetscErrorCode PCApplyTranspose_Composite_Additive(PC pc, Vec x, Vec y) {
143   PC_Composite    *jac  = (PC_Composite *)pc->data;
144   PC_CompositeLink next = jac->head;
145 
146   PetscFunctionBegin;
147   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
148   PetscCall(PCApplyTranspose(next->pc, x, y));
149   while (next->next) {
150     next = next->next;
151     PetscCall(PCApplyTranspose(next->pc, x, jac->work1));
152     PetscCall(VecAXPY(y, 1.0, jac->work1));
153   }
154   PetscFunctionReturn(0);
155 }
156 
157 static PetscErrorCode PCSetUp_Composite(PC pc) {
158   PC_Composite    *jac  = (PC_Composite *)pc->data;
159   PC_CompositeLink next = jac->head;
160   DM               dm;
161 
162   PetscFunctionBegin;
163   if (!jac->work1) PetscCall(MatCreateVecs(pc->pmat, &jac->work1, NULL));
164   PetscCall(PCGetDM(pc, &dm));
165   while (next) {
166     if (!next->pc->dm) PetscCall(PCSetDM(next->pc, dm));
167     if (!next->pc->mat) PetscCall(PCSetOperators(next->pc, pc->mat, pc->pmat));
168     next = next->next;
169   }
170   PetscFunctionReturn(0);
171 }
172 
173 static PetscErrorCode PCReset_Composite(PC pc) {
174   PC_Composite    *jac  = (PC_Composite *)pc->data;
175   PC_CompositeLink next = jac->head;
176 
177   PetscFunctionBegin;
178   while (next) {
179     PetscCall(PCReset(next->pc));
180     next = next->next;
181   }
182   PetscCall(VecDestroy(&jac->work1));
183   PetscCall(VecDestroy(&jac->work2));
184   PetscFunctionReturn(0);
185 }
186 
187 static PetscErrorCode PCDestroy_Composite(PC pc) {
188   PC_Composite    *jac  = (PC_Composite *)pc->data;
189   PC_CompositeLink next = jac->head, next_tmp;
190 
191   PetscFunctionBegin;
192   PetscCall(PCReset_Composite(pc));
193   while (next) {
194     PetscCall(PCDestroy(&next->pc));
195     next_tmp = next;
196     next     = next->next;
197     PetscCall(PetscFree(next_tmp));
198   }
199   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", NULL));
200   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", NULL));
201   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", NULL));
202   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", NULL));
203   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", NULL));
204   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", NULL));
205   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", NULL));
206   PetscCall(PetscFree(pc->data));
207   PetscFunctionReturn(0);
208 }
209 
210 static PetscErrorCode PCSetFromOptions_Composite(PC pc, PetscOptionItems *PetscOptionsObject) {
211   PC_Composite    *jac  = (PC_Composite *)pc->data;
212   PetscInt         nmax = 8, i;
213   PC_CompositeLink next;
214   char            *pcs[8];
215   PetscBool        flg;
216 
217   PetscFunctionBegin;
218   PetscOptionsHeadBegin(PetscOptionsObject, "Composite preconditioner options");
219   PetscCall(PetscOptionsEnum("-pc_composite_type", "Type of composition", "PCCompositeSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&jac->type, &flg));
220   if (flg) PetscCall(PCCompositeSetType(pc, jac->type));
221   PetscCall(PetscOptionsStringArray("-pc_composite_pcs", "List of composite solvers", "PCCompositeAddPCType", pcs, &nmax, &flg));
222   if (flg) {
223     for (i = 0; i < nmax; i++) {
224       PetscCall(PCCompositeAddPCType(pc, pcs[i]));
225       PetscCall(PetscFree(pcs[i])); /* deallocate string pcs[i], which is allocated in PetscOptionsStringArray() */
226     }
227   }
228   PetscOptionsHeadEnd();
229 
230   next = jac->head;
231   while (next) {
232     PetscCall(PCSetFromOptions(next->pc));
233     next = next->next;
234   }
235   PetscFunctionReturn(0);
236 }
237 
238 static PetscErrorCode PCView_Composite(PC pc, PetscViewer viewer) {
239   PC_Composite    *jac  = (PC_Composite *)pc->data;
240   PC_CompositeLink next = jac->head;
241   PetscBool        iascii;
242 
243   PetscFunctionBegin;
244   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
245   if (iascii) {
246     PetscCall(PetscViewerASCIIPrintf(viewer, "Composite PC type - %s\n", PCCompositeTypes[jac->type]));
247     PetscCall(PetscViewerASCIIPrintf(viewer, "PCs on composite preconditioner follow\n"));
248     PetscCall(PetscViewerASCIIPrintf(viewer, "---------------------------------\n"));
249   }
250   if (iascii) PetscCall(PetscViewerASCIIPushTab(viewer));
251   while (next) {
252     PetscCall(PCView(next->pc, viewer));
253     next = next->next;
254   }
255   if (iascii) {
256     PetscCall(PetscViewerASCIIPopTab(viewer));
257     PetscCall(PetscViewerASCIIPrintf(viewer, "---------------------------------\n"));
258   }
259   PetscFunctionReturn(0);
260 }
261 
262 static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc, PetscScalar alpha) {
263   PC_Composite *jac = (PC_Composite *)pc->data;
264 
265   PetscFunctionBegin;
266   jac->alpha = alpha;
267   PetscFunctionReturn(0);
268 }
269 
270 static PetscErrorCode PCCompositeSetType_Composite(PC pc, PCCompositeType type) {
271   PC_Composite *jac = (PC_Composite *)pc->data;
272 
273   PetscFunctionBegin;
274   if (type == PC_COMPOSITE_ADDITIVE) {
275     pc->ops->apply          = PCApply_Composite_Additive;
276     pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
277   } else if (type == PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
278     pc->ops->apply          = PCApply_Composite_Multiplicative;
279     pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative;
280   } else if (type == PC_COMPOSITE_SPECIAL) {
281     pc->ops->apply          = PCApply_Composite_Special;
282     pc->ops->applytranspose = NULL;
283   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Unknown composite preconditioner type");
284   jac->type = type;
285   PetscFunctionReturn(0);
286 }
287 
288 static PetscErrorCode PCCompositeGetType_Composite(PC pc, PCCompositeType *type) {
289   PC_Composite *jac = (PC_Composite *)pc->data;
290 
291   PetscFunctionBegin;
292   *type = jac->type;
293   PetscFunctionReturn(0);
294 }
295 
296 static PetscErrorCode PCCompositeAddPC_Composite(PC pc, PC subpc) {
297   PC_Composite    *jac;
298   PC_CompositeLink next, ilink;
299   PetscInt         cnt = 0;
300   const char      *prefix;
301   char             newprefix[20];
302 
303   PetscFunctionBegin;
304   PetscCall(PetscNewLog(pc, &ilink));
305   ilink->next = NULL;
306   ilink->pc   = subpc;
307 
308   jac  = (PC_Composite *)pc->data;
309   next = jac->head;
310   if (!next) {
311     jac->head       = ilink;
312     ilink->previous = NULL;
313   } else {
314     cnt++;
315     while (next->next) {
316       next = next->next;
317       cnt++;
318     }
319     next->next      = ilink;
320     ilink->previous = next;
321   }
322   PetscCall(PCGetOptionsPrefix(pc, &prefix));
323   PetscCall(PCSetOptionsPrefix(subpc, prefix));
324   PetscCall(PetscSNPrintf(newprefix, 20, "sub_%d_", (int)cnt));
325   PetscCall(PCAppendOptionsPrefix(subpc, newprefix));
326   PetscCall(PetscObjectReference((PetscObject)subpc));
327   PetscFunctionReturn(0);
328 }
329 
330 static PetscErrorCode PCCompositeAddPCType_Composite(PC pc, PCType type) {
331   PC subpc;
332 
333   PetscFunctionBegin;
334   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &subpc));
335   PetscCall(PetscObjectIncrementTabLevel((PetscObject)subpc, (PetscObject)pc, 1));
336   PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)subpc));
337   PetscCall(PCCompositeAddPC_Composite(pc, subpc));
338   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
339   PetscCall(PCSetType(subpc, type));
340   PetscCall(PCDestroy(&subpc));
341   PetscFunctionReturn(0);
342 }
343 
344 static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc, PetscInt *n) {
345   PC_Composite    *jac;
346   PC_CompositeLink next;
347 
348   PetscFunctionBegin;
349   jac  = (PC_Composite *)pc->data;
350   next = jac->head;
351   *n   = 0;
352   while (next) {
353     next = next->next;
354     (*n)++;
355   }
356   PetscFunctionReturn(0);
357 }
358 
359 static PetscErrorCode PCCompositeGetPC_Composite(PC pc, PetscInt n, PC *subpc) {
360   PC_Composite    *jac;
361   PC_CompositeLink next;
362   PetscInt         i;
363 
364   PetscFunctionBegin;
365   jac  = (PC_Composite *)pc->data;
366   next = jac->head;
367   for (i = 0; i < n; i++) {
368     PetscCheck(next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Not enough PCs in composite preconditioner");
369     next = next->next;
370   }
371   *subpc = next->pc;
372   PetscFunctionReturn(0);
373 }
374 
375 /*@
376    PCCompositeSetType - Sets the type of composite preconditioner.
377 
378    Logically Collective on pc
379 
380    Input Parameters:
381 +  pc - the preconditioner context
382 -  type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`
383 
384    Options Database Key:
385 .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
386 
387    Level: advanced
388 
389 .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
390           `PCCompositeGetType()`
391 @*/
392 PetscErrorCode PCCompositeSetType(PC pc, PCCompositeType type) {
393   PetscFunctionBegin;
394   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
395   PetscValidLogicalCollectiveEnum(pc, type, 2);
396   PetscTryMethod(pc, "PCCompositeSetType_C", (PC, PCCompositeType), (pc, type));
397   PetscFunctionReturn(0);
398 }
399 
400 /*@
401    PCCompositeGetType - Gets the type of composite preconditioner.
402 
403    Logically Collective on pc
404 
405    Input Parameter:
406 .  pc - the preconditioner context
407 
408    Output Parameter:
409 .  type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`
410 
411    Level: advanced
412 
413 .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
414           `PCCompositeSetType()`
415 @*/
416 PetscErrorCode PCCompositeGetType(PC pc, PCCompositeType *type) {
417   PetscFunctionBegin;
418   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
419   PetscUseMethod(pc, "PCCompositeGetType_C", (PC, PCCompositeType *), (pc, type));
420   PetscFunctionReturn(0);
421 }
422 
423 /*@
424    PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner, `PC_COMPOSITE_SPECIAL`,
425      for alphaI + R + S
426 
427    Logically Collective on pc
428 
429    Input Parameters:
430 +  pc - the preconditioner context
431 -  alpha - scale on identity
432 
433    Level: Developer
434 
435 .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
436           `PCCompositeSetType()`, `PCCompositeGetType()`
437 @*/
438 PetscErrorCode PCCompositeSpecialSetAlpha(PC pc, PetscScalar alpha) {
439   PetscFunctionBegin;
440   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
441   PetscValidLogicalCollectiveScalar(pc, alpha, 2);
442   PetscTryMethod(pc, "PCCompositeSpecialSetAlpha_C", (PC, PetscScalar), (pc, alpha));
443   PetscFunctionReturn(0);
444 }
445 
446 /*@C
447   PCCompositeAddPCType - Adds another `PC` of the given type to the composite `PC`.
448 
449   Collective on pc
450 
451   Input Parameters:
452 + pc - the preconditioner context
453 - type - the type of the new preconditioner
454 
455   Level: intermediate
456 
457 .seealso: `PCCOMPOSITE`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
458 @*/
459 PetscErrorCode PCCompositeAddPCType(PC pc, PCType type) {
460   PetscFunctionBegin;
461   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
462   PetscTryMethod(pc, "PCCompositeAddPCType_C", (PC, PCType), (pc, type));
463   PetscFunctionReturn(0);
464 }
465 
466 /*@
467   PCCompositeAddPC - Adds another `PC` to the composite `PC`.
468 
469   Collective on pc
470 
471   Input Parameters:
472 + pc    - the preconditioner context
473 - subpc - the new preconditioner
474 
475    Level: intermediate
476 
477 .seealso: `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`
478 @*/
479 PetscErrorCode PCCompositeAddPC(PC pc, PC subpc) {
480   PetscFunctionBegin;
481   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
482   PetscValidHeaderSpecific(subpc, PC_CLASSID, 2);
483   PetscTryMethod(pc, "PCCompositeAddPC_C", (PC, PC), (pc, subpc));
484   PetscFunctionReturn(0);
485 }
486 
487 /*@
488    PCCompositeGetNumberPC - Gets the number of `PC` objects in the composite `PC`.
489 
490    Not Collective
491 
492    Input Parameter:
493 .  pc - the preconditioner context
494 
495    Output Parameter:
496 .  num - the number of sub pcs
497 
498    Level: Developer
499 
500 .seealso: `PCCOMPOSITE`, `PCCompositeGetPC()`, `PCCompositeAddPC()`,  `PCCompositeAddPCType()`
501 @*/
502 PetscErrorCode PCCompositeGetNumberPC(PC pc, PetscInt *num) {
503   PetscFunctionBegin;
504   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
505   PetscValidIntPointer(num, 2);
506   PetscUseMethod(pc, "PCCompositeGetNumberPC_C", (PC, PetscInt *), (pc, num));
507   PetscFunctionReturn(0);
508 }
509 
510 /*@
511    PCCompositeGetPC - Gets one of the `PC` objects in the composite `PC`.
512 
513    Not Collective
514 
515    Input Parameters:
516 +  pc - the preconditioner context
517 -  n - the number of the pc requested
518 
519    Output Parameter:
520 .  subpc - the PC requested
521 
522    Level: intermediate
523 
524     Note:
525     To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
526     call `PCSetOperators()` on that `PC`.
527 
528 .seealso: `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`, `PCSetOperators()`
529 @*/
530 PetscErrorCode PCCompositeGetPC(PC pc, PetscInt n, PC *subpc) {
531   PetscFunctionBegin;
532   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
533   PetscValidPointer(subpc, 3);
534   PetscUseMethod(pc, "PCCompositeGetPC_C", (PC, PetscInt, PC *), (pc, n, subpc));
535   PetscFunctionReturn(0);
536 }
537 
538 /*MC
539      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners
540 
541    Options Database Keys:
542 +  -pc_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
543 .  -pc_use_amat - activates `PCSetUseAmat()`
544 -  -pc_composite_pcs - <pc0,pc1,...> list of PCs to compose
545 
546    Level: intermediate
547 
548    Notes:
549    To use a Krylov method inside the composite preconditioner, set the `PCType` of one or more
550    inner `PC`s to be `PCKSP`. Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
551    the incorrect answer) unless you use `KSPFGMRES` as the outer Krylov method
552 
553    To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
554    call `PCSetOperators()` on that `PC`.
555 
556 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
557           `PCSHELL`, `PCKSP`, `PCCompositeSetType()`, `PCCompositeSpecialSetAlpha()`, `PCCompositeAddPCType()`,
558           `PCCompositeGetPC()`, `PCSetUseAmat()`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
559 M*/
560 
561 PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc) {
562   PC_Composite *jac;
563 
564   PetscFunctionBegin;
565   PetscCall(PetscNewLog(pc, &jac));
566 
567   pc->ops->apply           = PCApply_Composite_Additive;
568   pc->ops->applytranspose  = PCApplyTranspose_Composite_Additive;
569   pc->ops->setup           = PCSetUp_Composite;
570   pc->ops->reset           = PCReset_Composite;
571   pc->ops->destroy         = PCDestroy_Composite;
572   pc->ops->setfromoptions  = PCSetFromOptions_Composite;
573   pc->ops->view            = PCView_Composite;
574   pc->ops->applyrichardson = NULL;
575 
576   pc->data   = (void *)jac;
577   jac->type  = PC_COMPOSITE_ADDITIVE;
578   jac->work1 = NULL;
579   jac->work2 = NULL;
580   jac->head  = NULL;
581 
582   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", PCCompositeSetType_Composite));
583   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", PCCompositeGetType_Composite));
584   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", PCCompositeAddPCType_Composite));
585   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", PCCompositeAddPC_Composite));
586   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", PCCompositeGetNumberPC_Composite));
587   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", PCCompositeGetPC_Composite));
588   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", PCCompositeSpecialSetAlpha_Composite));
589   PetscFunctionReturn(0);
590 }
591