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