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