xref: /petsc/src/ksp/pc/impls/composite/composite.c (revision f1580f4e3ce5d5b2393648fd039d0d41b440385d)
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 */
75ad540459SPierre Jolivet   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;
16348a46eb9SPierre Jolivet   if (!jac->work1) PetscCall(MatCreateVecs(pc->pmat, &jac->work1, NULL));
1649566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
1654b9ad928SBarry Smith   while (next) {
16648a46eb9SPierre Jolivet     if (!next->pc->dm) PetscCall(PCSetDM(next->pc, dm));
16748a46eb9SPierre 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 
2629371c9d4SSatish Balay static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc, PetscScalar alpha) {
2634b9ad928SBarry Smith   PC_Composite *jac = (PC_Composite *)pc->data;
2645fd66863SKarl Rupp 
2654b9ad928SBarry Smith   PetscFunctionBegin;
2664b9ad928SBarry Smith   jac->alpha = alpha;
2674b9ad928SBarry Smith   PetscFunctionReturn(0);
2684b9ad928SBarry Smith }
2694b9ad928SBarry Smith 
2709371c9d4SSatish Balay static PetscErrorCode PCCompositeSetType_Composite(PC pc, PCCompositeType type) {
271fad69fbaSJed Brown   PC_Composite *jac = (PC_Composite *)pc->data;
272fad69fbaSJed Brown 
2734b9ad928SBarry Smith   PetscFunctionBegin;
2744b9ad928SBarry Smith   if (type == PC_COMPOSITE_ADDITIVE) {
2754b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Additive;
2762533e041SBarry Smith     pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
277421e10b8SBarry Smith   } else if (type == PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
2784b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Multiplicative;
2792533e041SBarry Smith     pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative;
2804b9ad928SBarry Smith   } else if (type == PC_COMPOSITE_SPECIAL) {
2814b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Special;
2820298fd71SBarry Smith     pc->ops->applytranspose = NULL;
283a7261c6bSprj-   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Unknown composite preconditioner type");
284fad69fbaSJed Brown   jac->type = type;
2854b9ad928SBarry Smith   PetscFunctionReturn(0);
2864b9ad928SBarry Smith }
2874b9ad928SBarry Smith 
2889371c9d4SSatish Balay static PetscErrorCode PCCompositeGetType_Composite(PC pc, PCCompositeType *type) {
289c60c7ad4SBarry Smith   PC_Composite *jac = (PC_Composite *)pc->data;
290c60c7ad4SBarry Smith 
291c60c7ad4SBarry Smith   PetscFunctionBegin;
292c60c7ad4SBarry Smith   *type = jac->type;
293c60c7ad4SBarry Smith   PetscFunctionReturn(0);
294c60c7ad4SBarry Smith }
295c60c7ad4SBarry Smith 
2969371c9d4SSatish Balay static PetscErrorCode PCCompositeAddPC_Composite(PC pc, PC subpc) {
2974b9ad928SBarry Smith   PC_Composite    *jac;
2985a9f2f41SSatish Balay   PC_CompositeLink next, ilink;
29979416396SBarry Smith   PetscInt         cnt = 0;
3002dcb1b2aSMatthew Knepley   const char      *prefix;
301d726e3a5SJed Brown   char             newprefix[20];
3024b9ad928SBarry Smith 
3034b9ad928SBarry Smith   PetscFunctionBegin;
3049566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &ilink));
3050a545947SLisandro Dalcin   ilink->next = NULL;
3068aa07aa6SMatthew G. Knepley   ilink->pc   = subpc;
3074b9ad928SBarry Smith 
3084b9ad928SBarry Smith   jac  = (PC_Composite *)pc->data;
3094b9ad928SBarry Smith   next = jac->head;
3104b9ad928SBarry Smith   if (!next) {
3115a9f2f41SSatish Balay     jac->head       = ilink;
3120298fd71SBarry Smith     ilink->previous = NULL;
3134b9ad928SBarry Smith   } else {
3144b9ad928SBarry Smith     cnt++;
3154b9ad928SBarry Smith     while (next->next) {
3164b9ad928SBarry Smith       next = next->next;
3174b9ad928SBarry Smith       cnt++;
3184b9ad928SBarry Smith     }
3195a9f2f41SSatish Balay     next->next      = ilink;
320421e10b8SBarry Smith     ilink->previous = next;
3214b9ad928SBarry Smith   }
3229566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
3239566063dSJacob Faibussowitsch   PetscCall(PCSetOptionsPrefix(subpc, prefix));
3249566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(newprefix, 20, "sub_%d_", (int)cnt));
3259566063dSJacob Faibussowitsch   PetscCall(PCAppendOptionsPrefix(subpc, newprefix));
3269566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)subpc));
3278aa07aa6SMatthew G. Knepley   PetscFunctionReturn(0);
3288aa07aa6SMatthew G. Knepley }
3298aa07aa6SMatthew G. Knepley 
3309371c9d4SSatish Balay static PetscErrorCode PCCompositeAddPCType_Composite(PC pc, PCType type) {
3318aa07aa6SMatthew G. Knepley   PC subpc;
3328aa07aa6SMatthew G. Knepley 
3338aa07aa6SMatthew G. Knepley   PetscFunctionBegin;
3349566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &subpc));
3359566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)subpc, (PetscObject)pc, 1));
3369566063dSJacob Faibussowitsch   PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)subpc));
3379566063dSJacob Faibussowitsch   PetscCall(PCCompositeAddPC_Composite(pc, subpc));
3384b9ad928SBarry Smith   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
3399566063dSJacob Faibussowitsch   PetscCall(PCSetType(subpc, type));
3409566063dSJacob Faibussowitsch   PetscCall(PCDestroy(&subpc));
3414b9ad928SBarry Smith   PetscFunctionReturn(0);
3424b9ad928SBarry Smith }
3434b9ad928SBarry Smith 
3449371c9d4SSatish Balay static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc, PetscInt *n) {
3458e6eba06SBarry Smith   PC_Composite    *jac;
3468e6eba06SBarry Smith   PC_CompositeLink next;
3478e6eba06SBarry Smith 
3488e6eba06SBarry Smith   PetscFunctionBegin;
3498e6eba06SBarry Smith   jac  = (PC_Composite *)pc->data;
3508e6eba06SBarry Smith   next = jac->head;
3518e6eba06SBarry Smith   *n   = 0;
3528e6eba06SBarry Smith   while (next) {
3538e6eba06SBarry Smith     next = next->next;
3548e6eba06SBarry Smith     (*n)++;
3558e6eba06SBarry Smith   }
3568e6eba06SBarry Smith   PetscFunctionReturn(0);
3578e6eba06SBarry Smith }
3588e6eba06SBarry Smith 
3599371c9d4SSatish Balay static PetscErrorCode PCCompositeGetPC_Composite(PC pc, PetscInt n, PC *subpc) {
3604b9ad928SBarry Smith   PC_Composite    *jac;
3614b9ad928SBarry Smith   PC_CompositeLink next;
36279416396SBarry Smith   PetscInt         i;
3634b9ad928SBarry Smith 
3644b9ad928SBarry Smith   PetscFunctionBegin;
3654b9ad928SBarry Smith   jac  = (PC_Composite *)pc->data;
3664b9ad928SBarry Smith   next = jac->head;
3674b9ad928SBarry Smith   for (i = 0; i < n; i++) {
36828b400f6SJacob Faibussowitsch     PetscCheck(next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Not enough PCs in composite preconditioner");
3694b9ad928SBarry Smith     next = next->next;
3704b9ad928SBarry Smith   }
3714b9ad928SBarry Smith   *subpc = next->pc;
3724b9ad928SBarry Smith   PetscFunctionReturn(0);
3734b9ad928SBarry Smith }
3744b9ad928SBarry Smith 
375f39d8e23SSatish Balay /*@
3764b9ad928SBarry Smith    PCCompositeSetType - Sets the type of composite preconditioner.
3774b9ad928SBarry Smith 
378*f1580f4eSBarry Smith    Logically Collective on pc
3794b9ad928SBarry Smith 
380c60c7ad4SBarry Smith    Input Parameters:
3812a6744ebSBarry Smith +  pc - the preconditioner context
382*f1580f4eSBarry Smith -  type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`
3834b9ad928SBarry Smith 
3844b9ad928SBarry Smith    Options Database Key:
3854b9ad928SBarry Smith .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
3864b9ad928SBarry Smith 
387*f1580f4eSBarry Smith    Level: advanced
3884b9ad928SBarry Smith 
389*f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
390*f1580f4eSBarry Smith           `PCCompositeGetType()`
3914b9ad928SBarry Smith @*/
3929371c9d4SSatish Balay PetscErrorCode PCCompositeSetType(PC pc, PCCompositeType type) {
3934b9ad928SBarry Smith   PetscFunctionBegin;
3940700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
395c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, type, 2);
396cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeSetType_C", (PC, PCCompositeType), (pc, type));
3974b9ad928SBarry Smith   PetscFunctionReturn(0);
3984b9ad928SBarry Smith }
3994b9ad928SBarry Smith 
400c60c7ad4SBarry Smith /*@
401721f67b5SBarry Smith    PCCompositeGetType - Gets the type of composite preconditioner.
402c60c7ad4SBarry Smith 
403*f1580f4eSBarry Smith    Logically Collective on pc
404c60c7ad4SBarry Smith 
405c60c7ad4SBarry Smith    Input Parameter:
406c60c7ad4SBarry Smith .  pc - the preconditioner context
407c60c7ad4SBarry Smith 
408c60c7ad4SBarry Smith    Output Parameter:
409*f1580f4eSBarry Smith .  type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`
410c60c7ad4SBarry Smith 
411*f1580f4eSBarry Smith    Level: advanced
412c60c7ad4SBarry Smith 
413*f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
414*f1580f4eSBarry Smith           `PCCompositeSetType()`
415c60c7ad4SBarry Smith @*/
4169371c9d4SSatish Balay PetscErrorCode PCCompositeGetType(PC pc, PCCompositeType *type) {
417c60c7ad4SBarry Smith   PetscFunctionBegin;
418c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
419cac4c232SBarry Smith   PetscUseMethod(pc, "PCCompositeGetType_C", (PC, PCCompositeType *), (pc, type));
420c60c7ad4SBarry Smith   PetscFunctionReturn(0);
421c60c7ad4SBarry Smith }
422c60c7ad4SBarry Smith 
423f39d8e23SSatish Balay /*@
424*f1580f4eSBarry Smith    PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner, `PC_COMPOSITE_SPECIAL`,
4254b9ad928SBarry Smith      for alphaI + R + S
4264b9ad928SBarry Smith 
427*f1580f4eSBarry Smith    Logically Collective on pc
4284b9ad928SBarry Smith 
429d8d19677SJose E. Roman    Input Parameters:
4304b9ad928SBarry Smith +  pc - the preconditioner context
4314b9ad928SBarry Smith -  alpha - scale on identity
4324b9ad928SBarry Smith 
4334b9ad928SBarry Smith    Level: Developer
4344b9ad928SBarry Smith 
435*f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
436*f1580f4eSBarry Smith           `PCCompositeSetType()`, `PCCompositeGetType()`
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
447*f1580f4eSBarry Smith   PCCompositeAddPCType - Adds another `PC` of the given type to the composite `PC`.
4484b9ad928SBarry Smith 
449*f1580f4eSBarry 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 
455*f1580f4eSBarry Smith   Level: intermediate
4564b9ad928SBarry Smith 
457*f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
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 /*@
467*f1580f4eSBarry Smith   PCCompositeAddPC - Adds another `PC` to the composite `PC`.
4688aa07aa6SMatthew G. Knepley 
469*f1580f4eSBarry Smith   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 
475*f1580f4eSBarry Smith    Level: intermediate
4768aa07aa6SMatthew G. Knepley 
477*f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`
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 /*@
488*f1580f4eSBarry 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 
500*f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PCCompositeGetPC()`, `PCCompositeAddPC()`,  `PCCompositeAddPCType()`
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 /*@
511*f1580f4eSBarry 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 
519*f1580f4eSBarry Smith    Output Parameter:
5204b9ad928SBarry Smith .  subpc - the PC requested
5214b9ad928SBarry Smith 
522*f1580f4eSBarry Smith    Level: intermediate
5234b9ad928SBarry Smith 
524*f1580f4eSBarry Smith     Note:
525*f1580f4eSBarry Smith     To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
526*f1580f4eSBarry Smith     call `PCSetOperators()` on that `PC`.
5272b1d202aSBarry Smith 
528*f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `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 /*MC
5394b9ad928SBarry Smith      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners
5404b9ad928SBarry Smith 
5414b9ad928SBarry Smith    Options Database Keys:
5422eab2d5bSJungho Lee +  -pc_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
543*f1580f4eSBarry Smith .  -pc_use_amat - activates `PCSetUseAmat()`
54451f519a2SBarry Smith -  -pc_composite_pcs - <pc0,pc1,...> list of PCs to compose
5454b9ad928SBarry Smith 
5464b9ad928SBarry Smith    Level: intermediate
5474b9ad928SBarry Smith 
54895452b02SPatrick Sanan    Notes:
549*f1580f4eSBarry Smith    To use a Krylov method inside the composite preconditioner, set the `PCType` of one or more
550*f1580f4eSBarry Smith    inner `PC`s to be `PCKSP`. Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
551*f1580f4eSBarry Smith    the incorrect answer) unless you use `KSPFGMRES` as the outer Krylov method
552*f1580f4eSBarry Smith 
553*f1580f4eSBarry Smith    To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
554*f1580f4eSBarry Smith    call `PCSetOperators()` on that `PC`.
5554b9ad928SBarry Smith 
556db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
557db781477SPatrick Sanan           `PCSHELL`, `PCKSP`, `PCCompositeSetType()`, `PCCompositeSpecialSetAlpha()`, `PCCompositeAddPCType()`,
558*f1580f4eSBarry Smith           `PCCompositeGetPC()`, `PCSetUseAmat()`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
5594b9ad928SBarry Smith M*/
5604b9ad928SBarry Smith 
5619371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc) {
5624b9ad928SBarry Smith   PC_Composite *jac;
5634b9ad928SBarry Smith 
5644b9ad928SBarry Smith   PetscFunctionBegin;
5659566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(pc, &jac));
5662fa5cd67SKarl Rupp 
5674b9ad928SBarry Smith   pc->ops->apply           = PCApply_Composite_Additive;
5682533e041SBarry Smith   pc->ops->applytranspose  = PCApplyTranspose_Composite_Additive;
5694b9ad928SBarry Smith   pc->ops->setup           = PCSetUp_Composite;
57069d2c0f9SBarry Smith   pc->ops->reset           = PCReset_Composite;
5714b9ad928SBarry Smith   pc->ops->destroy         = PCDestroy_Composite;
5724b9ad928SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_Composite;
5734b9ad928SBarry Smith   pc->ops->view            = PCView_Composite;
5740a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
5754b9ad928SBarry Smith 
5764b9ad928SBarry Smith   pc->data   = (void *)jac;
5774b9ad928SBarry Smith   jac->type  = PC_COMPOSITE_ADDITIVE;
5780a545947SLisandro Dalcin   jac->work1 = NULL;
5790a545947SLisandro Dalcin   jac->work2 = NULL;
5800a545947SLisandro Dalcin   jac->head  = NULL;
5814b9ad928SBarry Smith 
5829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", PCCompositeSetType_Composite));
5839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", PCCompositeGetType_Composite));
5849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", PCCompositeAddPCType_Composite));
5859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", PCCompositeAddPC_Composite));
5869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", PCCompositeGetNumberPC_Composite));
5879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", PCCompositeGetPC_Composite));
5889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", PCCompositeSpecialSetAlpha_Composite));
5894b9ad928SBarry Smith   PetscFunctionReturn(0);
5904b9ad928SBarry Smith }
591