xref: /petsc/src/ksp/pc/impls/composite/composite.c (revision 66af8762ec03dbef0e079729eb2a1734a35ed7ff)
1 /*
2       Defines a preconditioner that can consist of a collection of PCs
3 */
4 #include <petsc/private/pcimpl.h>
5 #include <petscksp.h> /*I "petscksp.h" I*/
6 
7 typedef struct _PC_CompositeLink *PC_CompositeLink;
8 struct _PC_CompositeLink {
9   PC               pc;
10   PC_CompositeLink next;
11   PC_CompositeLink previous;
12 };
13 
14 typedef struct {
15   PC_CompositeLink head;
16   PCCompositeType  type;
17   Vec              work1;
18   Vec              work2;
19   PetscScalar      alpha;
20 } PC_Composite;
21 
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;
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(PETSC_SUCCESS);
61 }
62 
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;
68 
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 }
97 
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;
107 
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");
111 
112   /* Set the reuse flag on children PCs */
113   PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
114   PetscCall(PCSetReusePreconditioner(next->next->pc, pc->reusepreconditioner));
115 
116   PetscCall(PCApply(next->pc, x, jac->work1));
117   PetscCall(PCApply(next->next->pc, jac->work1, y));
118   PetscFunctionReturn(PETSC_SUCCESS);
119 }
120 
121 static PetscErrorCode PCApply_Composite_Additive(PC pc, Vec x, Vec y)
122 {
123   PC_Composite    *jac  = (PC_Composite *)pc->data;
124   PC_CompositeLink next = jac->head;
125 
126   PetscFunctionBegin;
127   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
128 
129   /* Set the reuse flag on children PCs */
130   while (next) {
131     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
132     next = next->next;
133   }
134   next = jac->head;
135 
136   PetscCall(PCApply(next->pc, x, y));
137   while (next->next) {
138     next = next->next;
139     PetscCall(PCApply(next->pc, x, jac->work1));
140     PetscCall(VecAXPY(y, 1.0, jac->work1));
141   }
142   PetscFunctionReturn(PETSC_SUCCESS);
143 }
144 
145 static PetscErrorCode PCApplyTranspose_Composite_Additive(PC pc, Vec x, Vec y)
146 {
147   PC_Composite    *jac  = (PC_Composite *)pc->data;
148   PC_CompositeLink next = jac->head;
149 
150   PetscFunctionBegin;
151   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
152   PetscCall(PCApplyTranspose(next->pc, x, y));
153   while (next->next) {
154     next = next->next;
155     PetscCall(PCApplyTranspose(next->pc, x, jac->work1));
156     PetscCall(VecAXPY(y, 1.0, jac->work1));
157   }
158   PetscFunctionReturn(PETSC_SUCCESS);
159 }
160 
161 static PetscErrorCode PCSetUp_Composite(PC pc)
162 {
163   PC_Composite    *jac  = (PC_Composite *)pc->data;
164   PC_CompositeLink next = jac->head;
165   DM               dm;
166 
167   PetscFunctionBegin;
168   if (!jac->work1) PetscCall(MatCreateVecs(pc->pmat, &jac->work1, NULL));
169   PetscCall(PCGetDM(pc, &dm));
170   while (next) {
171     if (!next->pc->dm) PetscCall(PCSetDM(next->pc, dm));
172     if (!next->pc->mat) PetscCall(PCSetOperators(next->pc, pc->mat, pc->pmat));
173     next = next->next;
174   }
175   PetscFunctionReturn(PETSC_SUCCESS);
176 }
177 
178 static PetscErrorCode PCSetUpOnBlocks_Composite(PC pc)
179 {
180   PC_Composite    *jac  = (PC_Composite *)pc->data;
181   PC_CompositeLink next = jac->head;
182   PCFailedReason   reason;
183 
184   PetscFunctionBegin;
185   while (next) {
186     PetscCall(PCSetUp(next->pc));
187     PetscCall(PCGetFailedReasonRank(next->pc, &reason));
188     if (reason) pc->failedreason = reason;
189     next = next->next;
190   }
191   PetscFunctionReturn(PETSC_SUCCESS);
192 }
193 
194 static PetscErrorCode PCReset_Composite(PC pc)
195 {
196   PC_Composite    *jac  = (PC_Composite *)pc->data;
197   PC_CompositeLink next = jac->head;
198 
199   PetscFunctionBegin;
200   while (next) {
201     PetscCall(PCReset(next->pc));
202     next = next->next;
203   }
204   PetscCall(VecDestroy(&jac->work1));
205   PetscCall(VecDestroy(&jac->work2));
206   PetscFunctionReturn(PETSC_SUCCESS);
207 }
208 
209 static PetscErrorCode PCDestroy_Composite(PC pc)
210 {
211   PC_Composite    *jac  = (PC_Composite *)pc->data;
212   PC_CompositeLink next = jac->head, next_tmp;
213 
214   PetscFunctionBegin;
215   PetscCall(PCReset_Composite(pc));
216   while (next) {
217     PetscCall(PCDestroy(&next->pc));
218     next_tmp = next;
219     next     = next->next;
220     PetscCall(PetscFree(next_tmp));
221   }
222   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", NULL));
223   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", NULL));
224   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", NULL));
225   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", NULL));
226   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", NULL));
227   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", NULL));
228   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", NULL));
229   PetscCall(PetscFree(pc->data));
230   PetscFunctionReturn(PETSC_SUCCESS);
231 }
232 
233 static PetscErrorCode PCSetFromOptions_Composite(PC pc, PetscOptionItems *PetscOptionsObject)
234 {
235   PC_Composite    *jac  = (PC_Composite *)pc->data;
236   PetscInt         nmax = 8, i;
237   PC_CompositeLink next;
238   char            *pcs[8];
239   PetscBool        flg;
240 
241   PetscFunctionBegin;
242   PetscOptionsHeadBegin(PetscOptionsObject, "Composite preconditioner options");
243   PetscCall(PetscOptionsEnum("-pc_composite_type", "Type of composition", "PCCompositeSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&jac->type, &flg));
244   if (flg) PetscCall(PCCompositeSetType(pc, jac->type));
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();
253 
254   next = jac->head;
255   while (next) {
256     PetscCall(PCSetFromOptions(next->pc));
257     next = next->next;
258   }
259   PetscFunctionReturn(PETSC_SUCCESS);
260 }
261 
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;
267 
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 }
286 
287 static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc, PetscScalar alpha)
288 {
289   PC_Composite *jac = (PC_Composite *)pc->data;
290 
291   PetscFunctionBegin;
292   jac->alpha = alpha;
293   PetscFunctionReturn(PETSC_SUCCESS);
294 }
295 
296 static PetscErrorCode PCCompositeSetType_Composite(PC pc, PCCompositeType type)
297 {
298   PC_Composite *jac = (PC_Composite *)pc->data;
299 
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 }
314 
315 static PetscErrorCode PCCompositeGetType_Composite(PC pc, PCCompositeType *type)
316 {
317   PC_Composite *jac = (PC_Composite *)pc->data;
318 
319   PetscFunctionBegin;
320   *type = jac->type;
321   PetscFunctionReturn(PETSC_SUCCESS);
322 }
323 
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];
331 
332   PetscFunctionBegin;
333   PetscCall(PetscNew(&ilink));
334   ilink->next = NULL;
335   ilink->pc   = subpc;
336 
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 }
358 
359 static PetscErrorCode PCCompositeAddPCType_Composite(PC pc, PCType type)
360 {
361   PC subpc;
362 
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 }
372 
373 static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc, PetscInt *n)
374 {
375   PC_Composite    *jac;
376   PC_CompositeLink next;
377 
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 }
388 
389 static PetscErrorCode PCCompositeGetPC_Composite(PC pc, PetscInt n, PC *subpc)
390 {
391   PC_Composite    *jac;
392   PC_CompositeLink next;
393   PetscInt         i;
394 
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 }
405 
406 /*@
407   PCCompositeSetType - Sets the type of composite preconditioner.
408 
409   Logically Collective
410 
411   Input Parameters:
412 + pc   - the preconditioner context
413 - type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`
414 
415   Options Database Key:
416 . -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
417 
418   Level: advanced
419 
420 .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
421           `PCCompositeGetType()`
422 @*/
423 PetscErrorCode PCCompositeSetType(PC pc, PCCompositeType type)
424 {
425   PetscFunctionBegin;
426   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
427   PetscValidLogicalCollectiveEnum(pc, type, 2);
428   PetscTryMethod(pc, "PCCompositeSetType_C", (PC, PCCompositeType), (pc, type));
429   PetscFunctionReturn(PETSC_SUCCESS);
430 }
431 
432 /*@
433   PCCompositeGetType - Gets the type of composite preconditioner.
434 
435   Logically Collective
436 
437   Input Parameter:
438 . pc - the preconditioner context
439 
440   Output Parameter:
441 . type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`
442 
443   Level: advanced
444 
445 .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
446           `PCCompositeSetType()`
447 @*/
448 PetscErrorCode PCCompositeGetType(PC pc, PCCompositeType *type)
449 {
450   PetscFunctionBegin;
451   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
452   PetscUseMethod(pc, "PCCompositeGetType_C", (PC, PCCompositeType *), (pc, type));
453   PetscFunctionReturn(PETSC_SUCCESS);
454 }
455 
456 /*@
457   PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner, `PC_COMPOSITE_SPECIAL`,
458   for alphaI + R + S
459 
460   Logically Collective
461 
462   Input Parameters:
463 + pc    - the preconditioner context
464 - alpha - scale on identity
465 
466   Level: developer
467 
468 .seealso: `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;
474   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
475   PetscValidLogicalCollectiveScalar(pc, alpha, 2);
476   PetscTryMethod(pc, "PCCompositeSpecialSetAlpha_C", (PC, PetscScalar), (pc, alpha));
477   PetscFunctionReturn(PETSC_SUCCESS);
478 }
479 
480 /*@C
481   PCCompositeAddPCType - Adds another `PC` of the given type to the composite `PC`.
482 
483   Collective
484 
485   Input Parameters:
486 + pc   - the preconditioner context
487 - type - the type of the new preconditioner
488 
489   Level: intermediate
490 
491 .seealso: `PCCOMPOSITE`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
492 @*/
493 PetscErrorCode PCCompositeAddPCType(PC pc, PCType type)
494 {
495   PetscFunctionBegin;
496   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
497   PetscTryMethod(pc, "PCCompositeAddPCType_C", (PC, PCType), (pc, type));
498   PetscFunctionReturn(PETSC_SUCCESS);
499 }
500 
501 /*@
502   PCCompositeAddPC - Adds another `PC` to the composite `PC`.
503 
504   Collective
505 
506   Input Parameters:
507 + pc    - the preconditioner context
508 - subpc - the new preconditioner
509 
510   Level: intermediate
511 
512 .seealso: `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`
513 @*/
514 PetscErrorCode PCCompositeAddPC(PC pc, PC subpc)
515 {
516   PetscFunctionBegin;
517   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
518   PetscValidHeaderSpecific(subpc, PC_CLASSID, 2);
519   PetscTryMethod(pc, "PCCompositeAddPC_C", (PC, PC), (pc, subpc));
520   PetscFunctionReturn(PETSC_SUCCESS);
521 }
522 
523 /*@
524   PCCompositeGetNumberPC - Gets the number of `PC` objects in the composite `PC`.
525 
526   Not Collective
527 
528   Input Parameter:
529 . pc - the preconditioner context
530 
531   Output Parameter:
532 . num - the number of sub pcs
533 
534   Level: developer
535 
536 .seealso: `PCCOMPOSITE`, `PCCompositeGetPC()`, `PCCompositeAddPC()`, `PCCompositeAddPCType()`
537 @*/
538 PetscErrorCode PCCompositeGetNumberPC(PC pc, PetscInt *num)
539 {
540   PetscFunctionBegin;
541   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
542   PetscAssertPointer(num, 2);
543   PetscUseMethod(pc, "PCCompositeGetNumberPC_C", (PC, PetscInt *), (pc, num));
544   PetscFunctionReturn(PETSC_SUCCESS);
545 }
546 
547 /*@
548   PCCompositeGetPC - Gets one of the `PC` objects in the composite `PC`.
549 
550   Not Collective
551 
552   Input Parameters:
553 + pc - the preconditioner context
554 - n  - the number of the pc requested
555 
556   Output Parameter:
557 . subpc - the PC requested
558 
559   Level: intermediate
560 
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`.
564 
565 .seealso: `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`, `PCSetOperators()`
566 @*/
567 PetscErrorCode PCCompositeGetPC(PC pc, PetscInt n, PC *subpc)
568 {
569   PetscFunctionBegin;
570   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
571   PetscAssertPointer(subpc, 3);
572   PetscUseMethod(pc, "PCCompositeGetPC_C", (PC, PetscInt, PC *), (pc, n, subpc));
573   PetscFunctionReturn(PETSC_SUCCESS);
574 }
575 
576 /*MC
577      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners
578 
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
583 
584    Level: intermediate
585 
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
590 
591    To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
592    call `PCSetOperators()` on that `PC`.
593 
594 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
595           `PCSHELL`, `PCKSP`, `PCCompositeSetType()`, `PCCompositeSpecialSetAlpha()`, `PCCompositeAddPCType()`,
596           `PCCompositeGetPC()`, `PCSetUseAmat()`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
597 M*/
598 
599 PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc)
600 {
601   PC_Composite *jac;
602 
603   PetscFunctionBegin;
604   PetscCall(PetscNew(&jac));
605 
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;
615 
616   pc->data   = (void *)jac;
617   jac->type  = PC_COMPOSITE_ADDITIVE;
618   jac->work1 = NULL;
619   jac->work2 = NULL;
620   jac->head  = NULL;
621 
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 }
631