xref: /petsc/src/ksp/pc/impls/composite/composite.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
1dba47a55SKris Buschelman 
24b9ad928SBarry Smith /*
34b9ad928SBarry Smith       Defines a preconditioner that can consist of a collection of PCs
44b9ad928SBarry Smith */
5af0996ceSBarry Smith #include <petsc/private/pcimpl.h>
6c6db04a5SJed Brown #include <petscksp.h> /*I "petscksp.h" I*/
74b9ad928SBarry Smith 
84b9ad928SBarry Smith typedef struct _PC_CompositeLink *PC_CompositeLink;
94b9ad928SBarry Smith struct _PC_CompositeLink {
104b9ad928SBarry Smith   PC               pc;
114b9ad928SBarry Smith   PC_CompositeLink next;
12421e10b8SBarry Smith   PC_CompositeLink previous;
134b9ad928SBarry Smith };
144b9ad928SBarry Smith 
154b9ad928SBarry Smith typedef struct {
164b9ad928SBarry Smith   PC_CompositeLink head;
174b9ad928SBarry Smith   PCCompositeType  type;
184b9ad928SBarry Smith   Vec              work1;
194b9ad928SBarry Smith   Vec              work2;
204b9ad928SBarry Smith   PetscScalar      alpha;
214b9ad928SBarry Smith } PC_Composite;
224b9ad928SBarry Smith 
239371c9d4SSatish Balay static PetscErrorCode PCApply_Composite_Multiplicative(PC pc, Vec x, Vec y) {
244b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
254b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
264b9ad928SBarry Smith   Mat              mat  = pc->pmat;
274b9ad928SBarry Smith 
284b9ad928SBarry Smith   PetscFunctionBegin;
29450d59ebSPatrick Farrell 
3028b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
31450d59ebSPatrick Farrell 
32450d59ebSPatrick Farrell   /* Set the reuse flag on children PCs */
33450d59ebSPatrick Farrell   while (next) {
349566063dSJacob Faibussowitsch     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
35450d59ebSPatrick Farrell     next = next->next;
36450d59ebSPatrick Farrell   }
37450d59ebSPatrick Farrell   next = jac->head;
38450d59ebSPatrick Farrell 
394b9ad928SBarry Smith   if (next->next && !jac->work2) { /* allocate second work vector */
409566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(jac->work1, &jac->work2));
414b9ad928SBarry Smith   }
4249517cdeSBarry Smith   if (pc->useAmat) mat = pc->mat;
439566063dSJacob Faibussowitsch   PetscCall(PCApply(next->pc, x, y)); /* y <- B x */
444b9ad928SBarry Smith   while (next->next) {
454b9ad928SBarry Smith     next = next->next;
469566063dSJacob Faibussowitsch     PetscCall(MatMult(mat, y, jac->work1));               /* work1 <- A y */
479566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x)); /* work2 <- x - work1 */
489566063dSJacob Faibussowitsch     PetscCall(PCApply(next->pc, jac->work2, jac->work1)); /* work1 <- C work2 */
499566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, 1.0, jac->work1));               /* y <- y + work1 = B x + C (x - A B x) = (B + C (1 - A B)) x */
504b9ad928SBarry Smith   }
51421e10b8SBarry Smith   if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
52421e10b8SBarry Smith     while (next->previous) {
53421e10b8SBarry Smith       next = next->previous;
549566063dSJacob Faibussowitsch       PetscCall(MatMult(mat, y, jac->work1));
559566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
569566063dSJacob Faibussowitsch       PetscCall(PCApply(next->pc, jac->work2, jac->work1));
579566063dSJacob Faibussowitsch       PetscCall(VecAXPY(y, 1.0, jac->work1));
58421e10b8SBarry Smith     }
59421e10b8SBarry Smith   }
604b9ad928SBarry Smith   PetscFunctionReturn(0);
614b9ad928SBarry Smith }
624b9ad928SBarry Smith 
639371c9d4SSatish Balay static PetscErrorCode PCApplyTranspose_Composite_Multiplicative(PC pc, Vec x, Vec y) {
642533e041SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
652533e041SBarry Smith   PC_CompositeLink next = jac->head;
662533e041SBarry Smith   Mat              mat  = pc->pmat;
672533e041SBarry Smith 
682533e041SBarry Smith   PetscFunctionBegin;
6928b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
702533e041SBarry Smith   if (next->next && !jac->work2) { /* allocate second work vector */
719566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(jac->work1, &jac->work2));
722533e041SBarry Smith   }
7349517cdeSBarry Smith   if (pc->useAmat) mat = pc->mat;
742533e041SBarry Smith   /* locate last PC */
759371c9d4SSatish Balay   while (next->next) { next = next->next; }
769566063dSJacob Faibussowitsch   PetscCall(PCApplyTranspose(next->pc, x, y));
772533e041SBarry Smith   while (next->previous) {
782533e041SBarry Smith     next = next->previous;
799566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(mat, y, jac->work1));
809566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
819566063dSJacob Faibussowitsch     PetscCall(PCApplyTranspose(next->pc, jac->work2, jac->work1));
829566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, 1.0, jac->work1));
832533e041SBarry Smith   }
842533e041SBarry Smith   if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
852533e041SBarry Smith     next = jac->head;
862533e041SBarry Smith     while (next->next) {
872533e041SBarry Smith       next = next->next;
889566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(mat, y, jac->work1));
899566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
909566063dSJacob Faibussowitsch       PetscCall(PCApplyTranspose(next->pc, jac->work2, jac->work1));
919566063dSJacob Faibussowitsch       PetscCall(VecAXPY(y, 1.0, jac->work1));
922533e041SBarry Smith     }
932533e041SBarry Smith   }
942533e041SBarry Smith   PetscFunctionReturn(0);
952533e041SBarry Smith }
962533e041SBarry Smith 
974b9ad928SBarry Smith /*
984b9ad928SBarry Smith     This is very special for a matrix of the form alpha I + R + S
994b9ad928SBarry Smith where first preconditioner is built from alpha I + S and second from
1004b9ad928SBarry Smith alpha I + R
1014b9ad928SBarry Smith */
1029371c9d4SSatish Balay static PetscErrorCode PCApply_Composite_Special(PC pc, Vec x, Vec y) {
1034b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1044b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
1054b9ad928SBarry Smith 
1064b9ad928SBarry Smith   PetscFunctionBegin;
10728b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
1087827d75bSBarry Smith   PetscCheck(next->next && !next->next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Special composite preconditioners requires exactly two PCs");
1094b9ad928SBarry Smith 
110450d59ebSPatrick Farrell   /* Set the reuse flag on children PCs */
1119566063dSJacob Faibussowitsch   PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
1129566063dSJacob Faibussowitsch   PetscCall(PCSetReusePreconditioner(next->next->pc, pc->reusepreconditioner));
113450d59ebSPatrick Farrell 
1149566063dSJacob Faibussowitsch   PetscCall(PCApply(next->pc, x, jac->work1));
1159566063dSJacob Faibussowitsch   PetscCall(PCApply(next->next->pc, jac->work1, y));
1164b9ad928SBarry Smith   PetscFunctionReturn(0);
1174b9ad928SBarry Smith }
1184b9ad928SBarry Smith 
1199371c9d4SSatish Balay static PetscErrorCode PCApply_Composite_Additive(PC pc, Vec x, Vec y) {
1204b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1214b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
1224b9ad928SBarry Smith 
1234b9ad928SBarry Smith   PetscFunctionBegin;
12428b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
125450d59ebSPatrick Farrell 
126450d59ebSPatrick Farrell   /* Set the reuse flag on children PCs */
127450d59ebSPatrick Farrell   while (next) {
1289566063dSJacob Faibussowitsch     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
129450d59ebSPatrick Farrell     next = next->next;
130450d59ebSPatrick Farrell   }
131450d59ebSPatrick Farrell   next = jac->head;
132450d59ebSPatrick Farrell 
1339566063dSJacob Faibussowitsch   PetscCall(PCApply(next->pc, x, y));
1344b9ad928SBarry Smith   while (next->next) {
1354b9ad928SBarry Smith     next = next->next;
1369566063dSJacob Faibussowitsch     PetscCall(PCApply(next->pc, x, jac->work1));
1379566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, 1.0, jac->work1));
1384b9ad928SBarry Smith   }
1394b9ad928SBarry Smith   PetscFunctionReturn(0);
1404b9ad928SBarry Smith }
1414b9ad928SBarry Smith 
1429371c9d4SSatish Balay static PetscErrorCode PCApplyTranspose_Composite_Additive(PC pc, Vec x, Vec y) {
1432533e041SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1442533e041SBarry Smith   PC_CompositeLink next = jac->head;
1452533e041SBarry Smith 
1462533e041SBarry Smith   PetscFunctionBegin;
14728b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
1489566063dSJacob Faibussowitsch   PetscCall(PCApplyTranspose(next->pc, x, y));
1492533e041SBarry Smith   while (next->next) {
1502533e041SBarry Smith     next = next->next;
1519566063dSJacob Faibussowitsch     PetscCall(PCApplyTranspose(next->pc, x, jac->work1));
1529566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, 1.0, jac->work1));
1532533e041SBarry Smith   }
1542533e041SBarry Smith   PetscFunctionReturn(0);
1552533e041SBarry Smith }
1562533e041SBarry Smith 
1579371c9d4SSatish Balay static PetscErrorCode PCSetUp_Composite(PC pc) {
1584b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1594b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
1605a78d018SMatthew G. Knepley   DM               dm;
1614b9ad928SBarry Smith 
1624b9ad928SBarry Smith   PetscFunctionBegin;
163*48a46eb9SPierre Jolivet   if (!jac->work1) PetscCall(MatCreateVecs(pc->pmat, &jac->work1, NULL));
1649566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
1654b9ad928SBarry Smith   while (next) {
166*48a46eb9SPierre Jolivet     if (!next->pc->dm) PetscCall(PCSetDM(next->pc, dm));
167*48a46eb9SPierre Jolivet     if (!next->pc->mat) PetscCall(PCSetOperators(next->pc, pc->mat, pc->pmat));
1684b9ad928SBarry Smith     next = next->next;
1694b9ad928SBarry Smith   }
1704b9ad928SBarry Smith   PetscFunctionReturn(0);
1714b9ad928SBarry Smith }
1724b9ad928SBarry Smith 
1739371c9d4SSatish Balay static PetscErrorCode PCReset_Composite(PC pc) {
17469d2c0f9SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1755f48b12bSBarry Smith   PC_CompositeLink next = jac->head;
17669d2c0f9SBarry Smith 
17769d2c0f9SBarry Smith   PetscFunctionBegin;
17869d2c0f9SBarry Smith   while (next) {
1799566063dSJacob Faibussowitsch     PetscCall(PCReset(next->pc));
18069d2c0f9SBarry Smith     next = next->next;
18169d2c0f9SBarry Smith   }
1829566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->work1));
1839566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->work2));
18469d2c0f9SBarry Smith   PetscFunctionReturn(0);
18569d2c0f9SBarry Smith }
18669d2c0f9SBarry Smith 
1879371c9d4SSatish Balay static PetscErrorCode PCDestroy_Composite(PC pc) {
1884b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
189724c2c99SHong Zhang   PC_CompositeLink next = jac->head, next_tmp;
1904b9ad928SBarry Smith 
1914b9ad928SBarry Smith   PetscFunctionBegin;
1929566063dSJacob Faibussowitsch   PetscCall(PCReset_Composite(pc));
1934b9ad928SBarry Smith   while (next) {
1949566063dSJacob Faibussowitsch     PetscCall(PCDestroy(&next->pc));
195724c2c99SHong Zhang     next_tmp = next;
1964b9ad928SBarry Smith     next     = next->next;
1979566063dSJacob Faibussowitsch     PetscCall(PetscFree(next_tmp));
1984b9ad928SBarry Smith   }
1992e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", NULL));
2002e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", NULL));
2012e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", NULL));
2022e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", NULL));
2032e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", NULL));
2042e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", NULL));
2052e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", NULL));
2069566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
2074b9ad928SBarry Smith   PetscFunctionReturn(0);
2084b9ad928SBarry Smith }
2094b9ad928SBarry Smith 
2109371c9d4SSatish Balay static PetscErrorCode PCSetFromOptions_Composite(PC pc, PetscOptionItems *PetscOptionsObject) {
2114b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
2129dcbbd2bSBarry Smith   PetscInt         nmax = 8, i;
2134b9ad928SBarry Smith   PC_CompositeLink next;
214e5999256SBarry Smith   char            *pcs[8];
215ace3abfcSBarry Smith   PetscBool        flg;
2164b9ad928SBarry Smith 
2174b9ad928SBarry Smith   PetscFunctionBegin;
218d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Composite preconditioner options");
2199566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_composite_type", "Type of composition", "PCCompositeSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&jac->type, &flg));
2201baa6e33SBarry Smith   if (flg) PetscCall(PCCompositeSetType(pc, jac->type));
2219566063dSJacob Faibussowitsch   PetscCall(PetscOptionsStringArray("-pc_composite_pcs", "List of composite solvers", "PCCompositeAddPCType", pcs, &nmax, &flg));
2224b9ad928SBarry Smith   if (flg) {
2234b9ad928SBarry Smith     for (i = 0; i < nmax; i++) {
2249566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(pc, pcs[i]));
2259566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcs[i])); /* deallocate string pcs[i], which is allocated in PetscOptionsStringArray() */
2264b9ad928SBarry Smith     }
2274b9ad928SBarry Smith   }
228d0609cedSBarry Smith   PetscOptionsHeadEnd();
2294b9ad928SBarry Smith 
2304b9ad928SBarry Smith   next = jac->head;
2314b9ad928SBarry Smith   while (next) {
2329566063dSJacob Faibussowitsch     PetscCall(PCSetFromOptions(next->pc));
2334b9ad928SBarry Smith     next = next->next;
2344b9ad928SBarry Smith   }
2354b9ad928SBarry Smith   PetscFunctionReturn(0);
2364b9ad928SBarry Smith }
2374b9ad928SBarry Smith 
2389371c9d4SSatish Balay static PetscErrorCode PCView_Composite(PC pc, PetscViewer viewer) {
2394b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
2404b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
241ace3abfcSBarry Smith   PetscBool        iascii;
2424b9ad928SBarry Smith 
2434b9ad928SBarry Smith   PetscFunctionBegin;
2449566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
24532077d6dSBarry Smith   if (iascii) {
2469566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Composite PC type - %s\n", PCCompositeTypes[jac->type]));
2479566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "PCs on composite preconditioner follow\n"));
2489566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "---------------------------------\n"));
2494b9ad928SBarry Smith   }
2501baa6e33SBarry Smith   if (iascii) PetscCall(PetscViewerASCIIPushTab(viewer));
2514b9ad928SBarry Smith   while (next) {
2529566063dSJacob Faibussowitsch     PetscCall(PCView(next->pc, viewer));
2534b9ad928SBarry Smith     next = next->next;
2544b9ad928SBarry Smith   }
25532077d6dSBarry Smith   if (iascii) {
2569566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
2579566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "---------------------------------\n"));
2584b9ad928SBarry Smith   }
2594b9ad928SBarry Smith   PetscFunctionReturn(0);
2604b9ad928SBarry Smith }
2614b9ad928SBarry Smith 
2624b9ad928SBarry Smith /* ------------------------------------------------------------------------------*/
2634b9ad928SBarry Smith 
2649371c9d4SSatish Balay static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc, PetscScalar alpha) {
2654b9ad928SBarry Smith   PC_Composite *jac = (PC_Composite *)pc->data;
2665fd66863SKarl Rupp 
2674b9ad928SBarry Smith   PetscFunctionBegin;
2684b9ad928SBarry Smith   jac->alpha = alpha;
2694b9ad928SBarry Smith   PetscFunctionReturn(0);
2704b9ad928SBarry Smith }
2714b9ad928SBarry Smith 
2729371c9d4SSatish Balay static PetscErrorCode PCCompositeSetType_Composite(PC pc, PCCompositeType type) {
273fad69fbaSJed Brown   PC_Composite *jac = (PC_Composite *)pc->data;
274fad69fbaSJed Brown 
2754b9ad928SBarry Smith   PetscFunctionBegin;
2764b9ad928SBarry Smith   if (type == PC_COMPOSITE_ADDITIVE) {
2774b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Additive;
2782533e041SBarry Smith     pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
279421e10b8SBarry Smith   } else if (type == PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
2804b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Multiplicative;
2812533e041SBarry Smith     pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative;
2824b9ad928SBarry Smith   } else if (type == PC_COMPOSITE_SPECIAL) {
2834b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Special;
2840298fd71SBarry Smith     pc->ops->applytranspose = NULL;
285a7261c6bSprj-   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Unknown composite preconditioner type");
286fad69fbaSJed Brown   jac->type = type;
2874b9ad928SBarry Smith   PetscFunctionReturn(0);
2884b9ad928SBarry Smith }
2894b9ad928SBarry Smith 
2909371c9d4SSatish Balay static PetscErrorCode PCCompositeGetType_Composite(PC pc, PCCompositeType *type) {
291c60c7ad4SBarry Smith   PC_Composite *jac = (PC_Composite *)pc->data;
292c60c7ad4SBarry Smith 
293c60c7ad4SBarry Smith   PetscFunctionBegin;
294c60c7ad4SBarry Smith   *type = jac->type;
295c60c7ad4SBarry Smith   PetscFunctionReturn(0);
296c60c7ad4SBarry Smith }
297c60c7ad4SBarry Smith 
2989371c9d4SSatish Balay static PetscErrorCode PCCompositeAddPC_Composite(PC pc, PC subpc) {
2994b9ad928SBarry Smith   PC_Composite    *jac;
3005a9f2f41SSatish Balay   PC_CompositeLink next, ilink;
30179416396SBarry Smith   PetscInt         cnt = 0;
3022dcb1b2aSMatthew Knepley   const char      *prefix;
303d726e3a5SJed Brown   char             newprefix[20];
3044b9ad928SBarry Smith 
3054b9ad928SBarry Smith   PetscFunctionBegin;
3069566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &ilink));
3070a545947SLisandro Dalcin   ilink->next = NULL;
3088aa07aa6SMatthew G. Knepley   ilink->pc   = subpc;
3094b9ad928SBarry Smith 
3104b9ad928SBarry Smith   jac  = (PC_Composite *)pc->data;
3114b9ad928SBarry Smith   next = jac->head;
3124b9ad928SBarry Smith   if (!next) {
3135a9f2f41SSatish Balay     jac->head       = ilink;
3140298fd71SBarry Smith     ilink->previous = NULL;
3154b9ad928SBarry Smith   } else {
3164b9ad928SBarry Smith     cnt++;
3174b9ad928SBarry Smith     while (next->next) {
3184b9ad928SBarry Smith       next = next->next;
3194b9ad928SBarry Smith       cnt++;
3204b9ad928SBarry Smith     }
3215a9f2f41SSatish Balay     next->next      = ilink;
322421e10b8SBarry Smith     ilink->previous = next;
3234b9ad928SBarry Smith   }
3249566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
3259566063dSJacob Faibussowitsch   PetscCall(PCSetOptionsPrefix(subpc, prefix));
3269566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(newprefix, 20, "sub_%d_", (int)cnt));
3279566063dSJacob Faibussowitsch   PetscCall(PCAppendOptionsPrefix(subpc, newprefix));
3289566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)subpc));
3298aa07aa6SMatthew G. Knepley   PetscFunctionReturn(0);
3308aa07aa6SMatthew G. Knepley }
3318aa07aa6SMatthew G. Knepley 
3329371c9d4SSatish Balay static PetscErrorCode PCCompositeAddPCType_Composite(PC pc, PCType type) {
3338aa07aa6SMatthew G. Knepley   PC subpc;
3348aa07aa6SMatthew G. Knepley 
3358aa07aa6SMatthew G. Knepley   PetscFunctionBegin;
3369566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &subpc));
3379566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)subpc, (PetscObject)pc, 1));
3389566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)subpc));
3399566063dSJacob Faibussowitsch   PetscCall(PCCompositeAddPC_Composite(pc, subpc));
3404b9ad928SBarry Smith   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
3419566063dSJacob Faibussowitsch   PetscCall(PCSetType(subpc, type));
3429566063dSJacob Faibussowitsch   PetscCall(PCDestroy(&subpc));
3434b9ad928SBarry Smith   PetscFunctionReturn(0);
3444b9ad928SBarry Smith }
3454b9ad928SBarry Smith 
3469371c9d4SSatish Balay static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc, PetscInt *n) {
3478e6eba06SBarry Smith   PC_Composite    *jac;
3488e6eba06SBarry Smith   PC_CompositeLink next;
3498e6eba06SBarry Smith 
3508e6eba06SBarry Smith   PetscFunctionBegin;
3518e6eba06SBarry Smith   jac  = (PC_Composite *)pc->data;
3528e6eba06SBarry Smith   next = jac->head;
3538e6eba06SBarry Smith   *n   = 0;
3548e6eba06SBarry Smith   while (next) {
3558e6eba06SBarry Smith     next = next->next;
3568e6eba06SBarry Smith     (*n)++;
3578e6eba06SBarry Smith   }
3588e6eba06SBarry Smith   PetscFunctionReturn(0);
3598e6eba06SBarry Smith }
3608e6eba06SBarry Smith 
3619371c9d4SSatish Balay static PetscErrorCode PCCompositeGetPC_Composite(PC pc, PetscInt n, PC *subpc) {
3624b9ad928SBarry Smith   PC_Composite    *jac;
3634b9ad928SBarry Smith   PC_CompositeLink next;
36479416396SBarry Smith   PetscInt         i;
3654b9ad928SBarry Smith 
3664b9ad928SBarry Smith   PetscFunctionBegin;
3674b9ad928SBarry Smith   jac  = (PC_Composite *)pc->data;
3684b9ad928SBarry Smith   next = jac->head;
3694b9ad928SBarry Smith   for (i = 0; i < n; i++) {
37028b400f6SJacob Faibussowitsch     PetscCheck(next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Not enough PCs in composite preconditioner");
3714b9ad928SBarry Smith     next = next->next;
3724b9ad928SBarry Smith   }
3734b9ad928SBarry Smith   *subpc = next->pc;
3744b9ad928SBarry Smith   PetscFunctionReturn(0);
3754b9ad928SBarry Smith }
3764b9ad928SBarry Smith 
3774b9ad928SBarry Smith /* -------------------------------------------------------------------------------- */
378f39d8e23SSatish Balay /*@
3794b9ad928SBarry Smith    PCCompositeSetType - Sets the type of composite preconditioner.
3804b9ad928SBarry Smith 
381ad4df100SBarry Smith    Logically Collective on PC
3824b9ad928SBarry Smith 
383c60c7ad4SBarry Smith    Input Parameters:
3842a6744ebSBarry Smith +  pc - the preconditioner context
3852a6744ebSBarry Smith -  type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL
3864b9ad928SBarry Smith 
3874b9ad928SBarry Smith    Options Database Key:
3884b9ad928SBarry Smith .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
3894b9ad928SBarry Smith 
3904b9ad928SBarry Smith    Level: Developer
3914b9ad928SBarry Smith 
3924b9ad928SBarry Smith @*/
3939371c9d4SSatish Balay PetscErrorCode PCCompositeSetType(PC pc, PCCompositeType type) {
3944b9ad928SBarry Smith   PetscFunctionBegin;
3950700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
396c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, type, 2);
397cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeSetType_C", (PC, PCCompositeType), (pc, type));
3984b9ad928SBarry Smith   PetscFunctionReturn(0);
3994b9ad928SBarry Smith }
4004b9ad928SBarry Smith 
401c60c7ad4SBarry Smith /*@
402721f67b5SBarry Smith    PCCompositeGetType - Gets the type of composite preconditioner.
403c60c7ad4SBarry Smith 
404c60c7ad4SBarry Smith    Logically Collective on PC
405c60c7ad4SBarry Smith 
406c60c7ad4SBarry Smith    Input Parameter:
407c60c7ad4SBarry Smith .  pc - the preconditioner context
408c60c7ad4SBarry Smith 
409c60c7ad4SBarry Smith    Output Parameter:
410c60c7ad4SBarry Smith .  type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL
411c60c7ad4SBarry Smith 
412c60c7ad4SBarry Smith    Options Database Key:
413c60c7ad4SBarry Smith .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
414c60c7ad4SBarry Smith 
415c60c7ad4SBarry Smith    Level: Developer
416c60c7ad4SBarry Smith 
417c60c7ad4SBarry Smith @*/
4189371c9d4SSatish Balay PetscErrorCode PCCompositeGetType(PC pc, PCCompositeType *type) {
419c60c7ad4SBarry Smith   PetscFunctionBegin;
420c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
421cac4c232SBarry Smith   PetscUseMethod(pc, "PCCompositeGetType_C", (PC, PCCompositeType *), (pc, type));
422c60c7ad4SBarry Smith   PetscFunctionReturn(0);
423c60c7ad4SBarry Smith }
424c60c7ad4SBarry Smith 
425f39d8e23SSatish Balay /*@
4264b9ad928SBarry Smith    PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner
4274b9ad928SBarry Smith      for alphaI + R + S
4284b9ad928SBarry Smith 
429ad4df100SBarry Smith    Logically Collective on PC
4304b9ad928SBarry Smith 
431d8d19677SJose E. Roman    Input Parameters:
4324b9ad928SBarry Smith +  pc - the preconditioner context
4334b9ad928SBarry Smith -  alpha - scale on identity
4344b9ad928SBarry Smith 
4354b9ad928SBarry Smith    Level: Developer
4364b9ad928SBarry Smith 
4374b9ad928SBarry Smith @*/
4389371c9d4SSatish Balay PetscErrorCode PCCompositeSpecialSetAlpha(PC pc, PetscScalar alpha) {
4394b9ad928SBarry Smith   PetscFunctionBegin;
4400700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
441c5eb9154SBarry Smith   PetscValidLogicalCollectiveScalar(pc, alpha, 2);
442cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeSpecialSetAlpha_C", (PC, PetscScalar), (pc, alpha));
4434b9ad928SBarry Smith   PetscFunctionReturn(0);
4444b9ad928SBarry Smith }
4454b9ad928SBarry Smith 
4464b9ad928SBarry Smith /*@C
4478aa07aa6SMatthew G. Knepley   PCCompositeAddPCType - Adds another PC of the given type to the composite PC.
4484b9ad928SBarry Smith 
4494b9ad928SBarry Smith   Collective on PC
4504b9ad928SBarry Smith 
4514b9ad928SBarry Smith   Input Parameters:
4522a6744ebSBarry Smith + pc - the preconditioner context
4532a6744ebSBarry Smith - type - the type of the new preconditioner
4544b9ad928SBarry Smith 
4554b9ad928SBarry Smith   Level: Developer
4564b9ad928SBarry Smith 
457db781477SPatrick Sanan .seealso: `PCCompositeAddPC()`
4584b9ad928SBarry Smith @*/
4599371c9d4SSatish Balay PetscErrorCode PCCompositeAddPCType(PC pc, PCType type) {
4604b9ad928SBarry Smith   PetscFunctionBegin;
4610700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
462cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeAddPCType_C", (PC, PCType), (pc, type));
4638aa07aa6SMatthew G. Knepley   PetscFunctionReturn(0);
4648aa07aa6SMatthew G. Knepley }
4658aa07aa6SMatthew G. Knepley 
4668aa07aa6SMatthew G. Knepley /*@
4678aa07aa6SMatthew G. Knepley   PCCompositeAddPC - Adds another PC to the composite PC.
4688aa07aa6SMatthew G. Knepley 
4698aa07aa6SMatthew G. Knepley   Collective on PC
4708aa07aa6SMatthew G. Knepley 
4718aa07aa6SMatthew G. Knepley   Input Parameters:
4728aa07aa6SMatthew G. Knepley + pc    - the preconditioner context
4738aa07aa6SMatthew G. Knepley - subpc - the new preconditioner
4748aa07aa6SMatthew G. Knepley 
4758aa07aa6SMatthew G. Knepley    Level: Developer
4768aa07aa6SMatthew G. Knepley 
477db781477SPatrick Sanan .seealso: `PCCompositeAddPCType()`
4788aa07aa6SMatthew G. Knepley @*/
4799371c9d4SSatish Balay PetscErrorCode PCCompositeAddPC(PC pc, PC subpc) {
4808aa07aa6SMatthew G. Knepley   PetscFunctionBegin;
4818aa07aa6SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
4828aa07aa6SMatthew G. Knepley   PetscValidHeaderSpecific(subpc, PC_CLASSID, 2);
483cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeAddPC_C", (PC, PC), (pc, subpc));
4844b9ad928SBarry Smith   PetscFunctionReturn(0);
4854b9ad928SBarry Smith }
4864b9ad928SBarry Smith 
4878e6eba06SBarry Smith /*@
4888e6eba06SBarry Smith    PCCompositeGetNumberPC - Gets the number of PC objects in the composite PC.
4898e6eba06SBarry Smith 
4908e6eba06SBarry Smith    Not Collective
4918e6eba06SBarry Smith 
4928e6eba06SBarry Smith    Input Parameter:
4938e6eba06SBarry Smith .  pc - the preconditioner context
4948e6eba06SBarry Smith 
4958e6eba06SBarry Smith    Output Parameter:
4968e6eba06SBarry Smith .  num - the number of sub pcs
4978e6eba06SBarry Smith 
4988e6eba06SBarry Smith    Level: Developer
4998e6eba06SBarry Smith 
500db781477SPatrick Sanan .seealso: `PCCompositeGetPC()`
5018e6eba06SBarry Smith @*/
5029371c9d4SSatish Balay PetscErrorCode PCCompositeGetNumberPC(PC pc, PetscInt *num) {
5038e6eba06SBarry Smith   PetscFunctionBegin;
5048e6eba06SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
5058e6eba06SBarry Smith   PetscValidIntPointer(num, 2);
506cac4c232SBarry Smith   PetscUseMethod(pc, "PCCompositeGetNumberPC_C", (PC, PetscInt *), (pc, num));
5078e6eba06SBarry Smith   PetscFunctionReturn(0);
5088e6eba06SBarry Smith }
5098e6eba06SBarry Smith 
510f39d8e23SSatish Balay /*@
5114b9ad928SBarry Smith    PCCompositeGetPC - Gets one of the PC objects in the composite PC.
5124b9ad928SBarry Smith 
5134b9ad928SBarry Smith    Not Collective
5144b9ad928SBarry Smith 
515d8d19677SJose E. Roman    Input Parameters:
5162a6744ebSBarry Smith +  pc - the preconditioner context
5172a6744ebSBarry Smith -  n - the number of the pc requested
5184b9ad928SBarry Smith 
5194b9ad928SBarry Smith    Output Parameters:
5204b9ad928SBarry Smith .  subpc - the PC requested
5214b9ad928SBarry Smith 
5224b9ad928SBarry Smith    Level: Developer
5234b9ad928SBarry Smith 
52495452b02SPatrick Sanan     Notes:
52595452b02SPatrick Sanan     To use a different operator to construct one of the inner preconditioners first call PCCompositeGetPC(), then
5262b1d202aSBarry Smith             call PCSetOperators() on that PC.
5272b1d202aSBarry Smith 
528db781477SPatrick Sanan .seealso: `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`, `PCSetOperators()`
5294b9ad928SBarry Smith @*/
5309371c9d4SSatish Balay PetscErrorCode PCCompositeGetPC(PC pc, PetscInt n, PC *subpc) {
5314b9ad928SBarry Smith   PetscFunctionBegin;
5320700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
5334482741eSBarry Smith   PetscValidPointer(subpc, 3);
534cac4c232SBarry Smith   PetscUseMethod(pc, "PCCompositeGetPC_C", (PC, PetscInt, PC *), (pc, n, subpc));
5354b9ad928SBarry Smith   PetscFunctionReturn(0);
5364b9ad928SBarry Smith }
5374b9ad928SBarry Smith 
5384b9ad928SBarry Smith /* -------------------------------------------------------------------------------------------*/
5394b9ad928SBarry Smith 
5404b9ad928SBarry Smith /*MC
5414b9ad928SBarry Smith      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners
5424b9ad928SBarry Smith 
5434b9ad928SBarry Smith    Options Database Keys:
5442eab2d5bSJungho Lee +  -pc_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
5452b1d202aSBarry Smith .  -pc_use_amat - activates PCSetUseAmat()
54651f519a2SBarry Smith -  -pc_composite_pcs - <pc0,pc1,...> list of PCs to compose
5474b9ad928SBarry Smith 
5484b9ad928SBarry Smith    Level: intermediate
5494b9ad928SBarry Smith 
55095452b02SPatrick Sanan    Notes:
55195452b02SPatrick Sanan     To use a Krylov method inside the composite preconditioner, set the PCType of one or more
5524b9ad928SBarry Smith           inner PCs to be PCKSP.
5534b9ad928SBarry Smith           Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
554b3ef52cdSBarry Smith           the incorrect answer) unless you use KSPFGMRES as the outer Krylov method
5552b1d202aSBarry Smith           To use a different operator to construct one of the inner preconditioners first call PCCompositeGetPC(), then
5562b1d202aSBarry Smith           call PCSetOperators() on that PC.
5574b9ad928SBarry Smith 
558db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
559db781477SPatrick Sanan           `PCSHELL`, `PCKSP`, `PCCompositeSetType()`, `PCCompositeSpecialSetAlpha()`, `PCCompositeAddPCType()`,
560db781477SPatrick Sanan           `PCCompositeGetPC()`, `PCSetUseAmat()`
5614b9ad928SBarry Smith 
5624b9ad928SBarry Smith M*/
5634b9ad928SBarry Smith 
5649371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc) {
5654b9ad928SBarry Smith   PC_Composite *jac;
5664b9ad928SBarry Smith 
5674b9ad928SBarry Smith   PetscFunctionBegin;
5689566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &jac));
5692fa5cd67SKarl Rupp 
5704b9ad928SBarry Smith   pc->ops->apply           = PCApply_Composite_Additive;
5712533e041SBarry Smith   pc->ops->applytranspose  = PCApplyTranspose_Composite_Additive;
5724b9ad928SBarry Smith   pc->ops->setup           = PCSetUp_Composite;
57369d2c0f9SBarry Smith   pc->ops->reset           = PCReset_Composite;
5744b9ad928SBarry Smith   pc->ops->destroy         = PCDestroy_Composite;
5754b9ad928SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_Composite;
5764b9ad928SBarry Smith   pc->ops->view            = PCView_Composite;
5770a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
5784b9ad928SBarry Smith 
5794b9ad928SBarry Smith   pc->data   = (void *)jac;
5804b9ad928SBarry Smith   jac->type  = PC_COMPOSITE_ADDITIVE;
5810a545947SLisandro Dalcin   jac->work1 = NULL;
5820a545947SLisandro Dalcin   jac->work2 = NULL;
5830a545947SLisandro Dalcin   jac->head  = NULL;
5844b9ad928SBarry Smith 
5859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", PCCompositeSetType_Composite));
5869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", PCCompositeGetType_Composite));
5879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", PCCompositeAddPCType_Composite));
5889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", PCCompositeAddPC_Composite));
5899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", PCCompositeGetNumberPC_Composite));
5909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", PCCompositeGetPC_Composite));
5919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", PCCompositeSpecialSetAlpha_Composite));
5924b9ad928SBarry Smith   PetscFunctionReturn(0);
5934b9ad928SBarry Smith }
594