xref: /petsc/src/ksp/pc/impls/composite/composite.c (revision c3339decea92175325d9368fa13196bcd0e0e58b)
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 
23d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_Composite_Multiplicative(PC pc, Vec x, Vec y)
24d71ae5a4SJacob Faibussowitsch {
254b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
264b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
274b9ad928SBarry Smith   Mat              mat  = pc->pmat;
284b9ad928SBarry Smith 
294b9ad928SBarry Smith   PetscFunctionBegin;
30450d59ebSPatrick Farrell 
3128b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
32450d59ebSPatrick Farrell 
33450d59ebSPatrick Farrell   /* Set the reuse flag on children PCs */
34450d59ebSPatrick Farrell   while (next) {
359566063dSJacob Faibussowitsch     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
36450d59ebSPatrick Farrell     next = next->next;
37450d59ebSPatrick Farrell   }
38450d59ebSPatrick Farrell   next = jac->head;
39450d59ebSPatrick Farrell 
404b9ad928SBarry Smith   if (next->next && !jac->work2) { /* allocate second work vector */
419566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(jac->work1, &jac->work2));
424b9ad928SBarry Smith   }
4349517cdeSBarry Smith   if (pc->useAmat) mat = pc->mat;
449566063dSJacob Faibussowitsch   PetscCall(PCApply(next->pc, x, y)); /* y <- B x */
454b9ad928SBarry Smith   while (next->next) {
464b9ad928SBarry Smith     next = next->next;
479566063dSJacob Faibussowitsch     PetscCall(MatMult(mat, y, jac->work1));               /* work1 <- A y */
489566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x)); /* work2 <- x - work1 */
499566063dSJacob Faibussowitsch     PetscCall(PCApply(next->pc, jac->work2, jac->work1)); /* work1 <- C work2 */
509566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, 1.0, jac->work1));               /* y <- y + work1 = B x + C (x - A B x) = (B + C (1 - A B)) x */
514b9ad928SBarry Smith   }
52421e10b8SBarry Smith   if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
53421e10b8SBarry Smith     while (next->previous) {
54421e10b8SBarry Smith       next = next->previous;
559566063dSJacob Faibussowitsch       PetscCall(MatMult(mat, y, jac->work1));
569566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
579566063dSJacob Faibussowitsch       PetscCall(PCApply(next->pc, jac->work2, jac->work1));
589566063dSJacob Faibussowitsch       PetscCall(VecAXPY(y, 1.0, jac->work1));
59421e10b8SBarry Smith     }
60421e10b8SBarry Smith   }
614b9ad928SBarry Smith   PetscFunctionReturn(0);
624b9ad928SBarry Smith }
634b9ad928SBarry Smith 
64d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_Composite_Multiplicative(PC pc, Vec x, Vec y)
65d71ae5a4SJacob Faibussowitsch {
662533e041SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
672533e041SBarry Smith   PC_CompositeLink next = jac->head;
682533e041SBarry Smith   Mat              mat  = pc->pmat;
692533e041SBarry Smith 
702533e041SBarry Smith   PetscFunctionBegin;
7128b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
722533e041SBarry Smith   if (next->next && !jac->work2) { /* allocate second work vector */
739566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(jac->work1, &jac->work2));
742533e041SBarry Smith   }
7549517cdeSBarry Smith   if (pc->useAmat) mat = pc->mat;
762533e041SBarry Smith   /* locate last PC */
77ad540459SPierre Jolivet   while (next->next) next = next->next;
789566063dSJacob Faibussowitsch   PetscCall(PCApplyTranspose(next->pc, x, y));
792533e041SBarry Smith   while (next->previous) {
802533e041SBarry Smith     next = next->previous;
819566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(mat, y, jac->work1));
829566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
839566063dSJacob Faibussowitsch     PetscCall(PCApplyTranspose(next->pc, jac->work2, jac->work1));
849566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, 1.0, jac->work1));
852533e041SBarry Smith   }
862533e041SBarry Smith   if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
872533e041SBarry Smith     next = jac->head;
882533e041SBarry Smith     while (next->next) {
892533e041SBarry Smith       next = next->next;
909566063dSJacob Faibussowitsch       PetscCall(MatMultTranspose(mat, y, jac->work1));
919566063dSJacob Faibussowitsch       PetscCall(VecWAXPY(jac->work2, -1.0, jac->work1, x));
929566063dSJacob Faibussowitsch       PetscCall(PCApplyTranspose(next->pc, jac->work2, jac->work1));
939566063dSJacob Faibussowitsch       PetscCall(VecAXPY(y, 1.0, jac->work1));
942533e041SBarry Smith     }
952533e041SBarry Smith   }
962533e041SBarry Smith   PetscFunctionReturn(0);
972533e041SBarry Smith }
982533e041SBarry Smith 
994b9ad928SBarry Smith /*
1004b9ad928SBarry Smith     This is very special for a matrix of the form alpha I + R + S
1014b9ad928SBarry Smith where first preconditioner is built from alpha I + S and second from
1024b9ad928SBarry Smith alpha I + R
1034b9ad928SBarry Smith */
104d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_Composite_Special(PC pc, Vec x, Vec y)
105d71ae5a4SJacob Faibussowitsch {
1064b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1074b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
1084b9ad928SBarry Smith 
1094b9ad928SBarry Smith   PetscFunctionBegin;
11028b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
1117827d75bSBarry Smith   PetscCheck(next->next && !next->next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Special composite preconditioners requires exactly two PCs");
1124b9ad928SBarry Smith 
113450d59ebSPatrick Farrell   /* Set the reuse flag on children PCs */
1149566063dSJacob Faibussowitsch   PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
1159566063dSJacob Faibussowitsch   PetscCall(PCSetReusePreconditioner(next->next->pc, pc->reusepreconditioner));
116450d59ebSPatrick Farrell 
1179566063dSJacob Faibussowitsch   PetscCall(PCApply(next->pc, x, jac->work1));
1189566063dSJacob Faibussowitsch   PetscCall(PCApply(next->next->pc, jac->work1, y));
1194b9ad928SBarry Smith   PetscFunctionReturn(0);
1204b9ad928SBarry Smith }
1214b9ad928SBarry Smith 
122d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_Composite_Additive(PC pc, Vec x, Vec y)
123d71ae5a4SJacob Faibussowitsch {
1244b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1254b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
1264b9ad928SBarry Smith 
1274b9ad928SBarry Smith   PetscFunctionBegin;
12828b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
129450d59ebSPatrick Farrell 
130450d59ebSPatrick Farrell   /* Set the reuse flag on children PCs */
131450d59ebSPatrick Farrell   while (next) {
1329566063dSJacob Faibussowitsch     PetscCall(PCSetReusePreconditioner(next->pc, pc->reusepreconditioner));
133450d59ebSPatrick Farrell     next = next->next;
134450d59ebSPatrick Farrell   }
135450d59ebSPatrick Farrell   next = jac->head;
136450d59ebSPatrick Farrell 
1379566063dSJacob Faibussowitsch   PetscCall(PCApply(next->pc, x, y));
1384b9ad928SBarry Smith   while (next->next) {
1394b9ad928SBarry Smith     next = next->next;
1409566063dSJacob Faibussowitsch     PetscCall(PCApply(next->pc, x, jac->work1));
1419566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, 1.0, jac->work1));
1424b9ad928SBarry Smith   }
1434b9ad928SBarry Smith   PetscFunctionReturn(0);
1444b9ad928SBarry Smith }
1454b9ad928SBarry Smith 
146d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_Composite_Additive(PC pc, Vec x, Vec y)
147d71ae5a4SJacob Faibussowitsch {
1482533e041SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1492533e041SBarry Smith   PC_CompositeLink next = jac->head;
1502533e041SBarry Smith 
1512533e041SBarry Smith   PetscFunctionBegin;
15228b400f6SJacob Faibussowitsch   PetscCheck(next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "No composite preconditioners supplied via PCCompositeAddPCType() or -pc_composite_pcs");
1539566063dSJacob Faibussowitsch   PetscCall(PCApplyTranspose(next->pc, x, y));
1542533e041SBarry Smith   while (next->next) {
1552533e041SBarry Smith     next = next->next;
1569566063dSJacob Faibussowitsch     PetscCall(PCApplyTranspose(next->pc, x, jac->work1));
1579566063dSJacob Faibussowitsch     PetscCall(VecAXPY(y, 1.0, jac->work1));
1582533e041SBarry Smith   }
1592533e041SBarry Smith   PetscFunctionReturn(0);
1602533e041SBarry Smith }
1612533e041SBarry Smith 
162d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_Composite(PC pc)
163d71ae5a4SJacob Faibussowitsch {
1644b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1654b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
1665a78d018SMatthew G. Knepley   DM               dm;
1674b9ad928SBarry Smith 
1684b9ad928SBarry Smith   PetscFunctionBegin;
16948a46eb9SPierre Jolivet   if (!jac->work1) PetscCall(MatCreateVecs(pc->pmat, &jac->work1, NULL));
1709566063dSJacob Faibussowitsch   PetscCall(PCGetDM(pc, &dm));
1714b9ad928SBarry Smith   while (next) {
17248a46eb9SPierre Jolivet     if (!next->pc->dm) PetscCall(PCSetDM(next->pc, dm));
17348a46eb9SPierre Jolivet     if (!next->pc->mat) PetscCall(PCSetOperators(next->pc, pc->mat, pc->pmat));
1744b9ad928SBarry Smith     next = next->next;
1754b9ad928SBarry Smith   }
1764b9ad928SBarry Smith   PetscFunctionReturn(0);
1774b9ad928SBarry Smith }
1784b9ad928SBarry Smith 
179d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_Composite(PC pc)
180d71ae5a4SJacob Faibussowitsch {
18169d2c0f9SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
1825f48b12bSBarry Smith   PC_CompositeLink next = jac->head;
18369d2c0f9SBarry Smith 
18469d2c0f9SBarry Smith   PetscFunctionBegin;
18569d2c0f9SBarry Smith   while (next) {
1869566063dSJacob Faibussowitsch     PetscCall(PCReset(next->pc));
18769d2c0f9SBarry Smith     next = next->next;
18869d2c0f9SBarry Smith   }
1899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->work1));
1909566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->work2));
19169d2c0f9SBarry Smith   PetscFunctionReturn(0);
19269d2c0f9SBarry Smith }
19369d2c0f9SBarry Smith 
194d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_Composite(PC pc)
195d71ae5a4SJacob Faibussowitsch {
1964b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
197724c2c99SHong Zhang   PC_CompositeLink next = jac->head, next_tmp;
1984b9ad928SBarry Smith 
1994b9ad928SBarry Smith   PetscFunctionBegin;
2009566063dSJacob Faibussowitsch   PetscCall(PCReset_Composite(pc));
2014b9ad928SBarry Smith   while (next) {
2029566063dSJacob Faibussowitsch     PetscCall(PCDestroy(&next->pc));
203724c2c99SHong Zhang     next_tmp = next;
2044b9ad928SBarry Smith     next     = next->next;
2059566063dSJacob Faibussowitsch     PetscCall(PetscFree(next_tmp));
2064b9ad928SBarry Smith   }
2072e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", NULL));
2082e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", NULL));
2092e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", NULL));
2102e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", NULL));
2112e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", NULL));
2122e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", NULL));
2132e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", NULL));
2149566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
2154b9ad928SBarry Smith   PetscFunctionReturn(0);
2164b9ad928SBarry Smith }
2174b9ad928SBarry Smith 
218d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetFromOptions_Composite(PC pc, PetscOptionItems *PetscOptionsObject)
219d71ae5a4SJacob Faibussowitsch {
2204b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
2219dcbbd2bSBarry Smith   PetscInt         nmax = 8, i;
2224b9ad928SBarry Smith   PC_CompositeLink next;
223e5999256SBarry Smith   char            *pcs[8];
224ace3abfcSBarry Smith   PetscBool        flg;
2254b9ad928SBarry Smith 
2264b9ad928SBarry Smith   PetscFunctionBegin;
227d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Composite preconditioner options");
2289566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_composite_type", "Type of composition", "PCCompositeSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&jac->type, &flg));
2291baa6e33SBarry Smith   if (flg) PetscCall(PCCompositeSetType(pc, jac->type));
2309566063dSJacob Faibussowitsch   PetscCall(PetscOptionsStringArray("-pc_composite_pcs", "List of composite solvers", "PCCompositeAddPCType", pcs, &nmax, &flg));
2314b9ad928SBarry Smith   if (flg) {
2324b9ad928SBarry Smith     for (i = 0; i < nmax; i++) {
2339566063dSJacob Faibussowitsch       PetscCall(PCCompositeAddPCType(pc, pcs[i]));
2349566063dSJacob Faibussowitsch       PetscCall(PetscFree(pcs[i])); /* deallocate string pcs[i], which is allocated in PetscOptionsStringArray() */
2354b9ad928SBarry Smith     }
2364b9ad928SBarry Smith   }
237d0609cedSBarry Smith   PetscOptionsHeadEnd();
2384b9ad928SBarry Smith 
2394b9ad928SBarry Smith   next = jac->head;
2404b9ad928SBarry Smith   while (next) {
2419566063dSJacob Faibussowitsch     PetscCall(PCSetFromOptions(next->pc));
2424b9ad928SBarry Smith     next = next->next;
2434b9ad928SBarry Smith   }
2444b9ad928SBarry Smith   PetscFunctionReturn(0);
2454b9ad928SBarry Smith }
2464b9ad928SBarry Smith 
247d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_Composite(PC pc, PetscViewer viewer)
248d71ae5a4SJacob Faibussowitsch {
2494b9ad928SBarry Smith   PC_Composite    *jac  = (PC_Composite *)pc->data;
2504b9ad928SBarry Smith   PC_CompositeLink next = jac->head;
251ace3abfcSBarry Smith   PetscBool        iascii;
2524b9ad928SBarry Smith 
2534b9ad928SBarry Smith   PetscFunctionBegin;
2549566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
25532077d6dSBarry Smith   if (iascii) {
2569566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Composite PC type - %s\n", PCCompositeTypes[jac->type]));
2579566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "PCs on composite preconditioner follow\n"));
2589566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "---------------------------------\n"));
2594b9ad928SBarry Smith   }
2601baa6e33SBarry Smith   if (iascii) PetscCall(PetscViewerASCIIPushTab(viewer));
2614b9ad928SBarry Smith   while (next) {
2629566063dSJacob Faibussowitsch     PetscCall(PCView(next->pc, viewer));
2634b9ad928SBarry Smith     next = next->next;
2644b9ad928SBarry Smith   }
26532077d6dSBarry Smith   if (iascii) {
2669566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
2679566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "---------------------------------\n"));
2684b9ad928SBarry Smith   }
2694b9ad928SBarry Smith   PetscFunctionReturn(0);
2704b9ad928SBarry Smith }
2714b9ad928SBarry Smith 
272d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCCompositeSpecialSetAlpha_Composite(PC pc, PetscScalar alpha)
273d71ae5a4SJacob Faibussowitsch {
2744b9ad928SBarry Smith   PC_Composite *jac = (PC_Composite *)pc->data;
2755fd66863SKarl Rupp 
2764b9ad928SBarry Smith   PetscFunctionBegin;
2774b9ad928SBarry Smith   jac->alpha = alpha;
2784b9ad928SBarry Smith   PetscFunctionReturn(0);
2794b9ad928SBarry Smith }
2804b9ad928SBarry Smith 
281d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCCompositeSetType_Composite(PC pc, PCCompositeType type)
282d71ae5a4SJacob Faibussowitsch {
283fad69fbaSJed Brown   PC_Composite *jac = (PC_Composite *)pc->data;
284fad69fbaSJed Brown 
2854b9ad928SBarry Smith   PetscFunctionBegin;
2864b9ad928SBarry Smith   if (type == PC_COMPOSITE_ADDITIVE) {
2874b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Additive;
2882533e041SBarry Smith     pc->ops->applytranspose = PCApplyTranspose_Composite_Additive;
289421e10b8SBarry Smith   } else if (type == PC_COMPOSITE_MULTIPLICATIVE || type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
2904b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Multiplicative;
2912533e041SBarry Smith     pc->ops->applytranspose = PCApplyTranspose_Composite_Multiplicative;
2924b9ad928SBarry Smith   } else if (type == PC_COMPOSITE_SPECIAL) {
2934b9ad928SBarry Smith     pc->ops->apply          = PCApply_Composite_Special;
2940298fd71SBarry Smith     pc->ops->applytranspose = NULL;
295a7261c6bSprj-   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Unknown composite preconditioner type");
296fad69fbaSJed Brown   jac->type = type;
2974b9ad928SBarry Smith   PetscFunctionReturn(0);
2984b9ad928SBarry Smith }
2994b9ad928SBarry Smith 
300d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCCompositeGetType_Composite(PC pc, PCCompositeType *type)
301d71ae5a4SJacob Faibussowitsch {
302c60c7ad4SBarry Smith   PC_Composite *jac = (PC_Composite *)pc->data;
303c60c7ad4SBarry Smith 
304c60c7ad4SBarry Smith   PetscFunctionBegin;
305c60c7ad4SBarry Smith   *type = jac->type;
306c60c7ad4SBarry Smith   PetscFunctionReturn(0);
307c60c7ad4SBarry Smith }
308c60c7ad4SBarry Smith 
309d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCCompositeAddPC_Composite(PC pc, PC subpc)
310d71ae5a4SJacob Faibussowitsch {
3114b9ad928SBarry Smith   PC_Composite    *jac;
3125a9f2f41SSatish Balay   PC_CompositeLink next, ilink;
31379416396SBarry Smith   PetscInt         cnt = 0;
3142dcb1b2aSMatthew Knepley   const char      *prefix;
315d726e3a5SJed Brown   char             newprefix[20];
3164b9ad928SBarry Smith 
3174b9ad928SBarry Smith   PetscFunctionBegin;
3184dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
3190a545947SLisandro Dalcin   ilink->next = NULL;
3208aa07aa6SMatthew G. Knepley   ilink->pc   = subpc;
3214b9ad928SBarry Smith 
3224b9ad928SBarry Smith   jac  = (PC_Composite *)pc->data;
3234b9ad928SBarry Smith   next = jac->head;
3244b9ad928SBarry Smith   if (!next) {
3255a9f2f41SSatish Balay     jac->head       = ilink;
3260298fd71SBarry Smith     ilink->previous = NULL;
3274b9ad928SBarry Smith   } else {
3284b9ad928SBarry Smith     cnt++;
3294b9ad928SBarry Smith     while (next->next) {
3304b9ad928SBarry Smith       next = next->next;
3314b9ad928SBarry Smith       cnt++;
3324b9ad928SBarry Smith     }
3335a9f2f41SSatish Balay     next->next      = ilink;
334421e10b8SBarry Smith     ilink->previous = next;
3354b9ad928SBarry Smith   }
3369566063dSJacob Faibussowitsch   PetscCall(PCGetOptionsPrefix(pc, &prefix));
3379566063dSJacob Faibussowitsch   PetscCall(PCSetOptionsPrefix(subpc, prefix));
3389566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(newprefix, 20, "sub_%d_", (int)cnt));
3399566063dSJacob Faibussowitsch   PetscCall(PCAppendOptionsPrefix(subpc, newprefix));
3409566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)subpc));
3418aa07aa6SMatthew G. Knepley   PetscFunctionReturn(0);
3428aa07aa6SMatthew G. Knepley }
3438aa07aa6SMatthew G. Knepley 
344d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCCompositeAddPCType_Composite(PC pc, PCType type)
345d71ae5a4SJacob Faibussowitsch {
3468aa07aa6SMatthew G. Knepley   PC subpc;
3478aa07aa6SMatthew G. Knepley 
3488aa07aa6SMatthew G. Knepley   PetscFunctionBegin;
3499566063dSJacob Faibussowitsch   PetscCall(PCCreate(PetscObjectComm((PetscObject)pc), &subpc));
3509566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)subpc, (PetscObject)pc, 1));
3519566063dSJacob Faibussowitsch   PetscCall(PCCompositeAddPC_Composite(pc, subpc));
3524b9ad928SBarry Smith   /* type is set after prefix, because some methods may modify prefix, e.g. pcksp */
3539566063dSJacob Faibussowitsch   PetscCall(PCSetType(subpc, type));
3549566063dSJacob Faibussowitsch   PetscCall(PCDestroy(&subpc));
3554b9ad928SBarry Smith   PetscFunctionReturn(0);
3564b9ad928SBarry Smith }
3574b9ad928SBarry Smith 
358d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCCompositeGetNumberPC_Composite(PC pc, PetscInt *n)
359d71ae5a4SJacob Faibussowitsch {
3608e6eba06SBarry Smith   PC_Composite    *jac;
3618e6eba06SBarry Smith   PC_CompositeLink next;
3628e6eba06SBarry Smith 
3638e6eba06SBarry Smith   PetscFunctionBegin;
3648e6eba06SBarry Smith   jac  = (PC_Composite *)pc->data;
3658e6eba06SBarry Smith   next = jac->head;
3668e6eba06SBarry Smith   *n   = 0;
3678e6eba06SBarry Smith   while (next) {
3688e6eba06SBarry Smith     next = next->next;
3698e6eba06SBarry Smith     (*n)++;
3708e6eba06SBarry Smith   }
3718e6eba06SBarry Smith   PetscFunctionReturn(0);
3728e6eba06SBarry Smith }
3738e6eba06SBarry Smith 
374d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCCompositeGetPC_Composite(PC pc, PetscInt n, PC *subpc)
375d71ae5a4SJacob Faibussowitsch {
3764b9ad928SBarry Smith   PC_Composite    *jac;
3774b9ad928SBarry Smith   PC_CompositeLink next;
37879416396SBarry Smith   PetscInt         i;
3794b9ad928SBarry Smith 
3804b9ad928SBarry Smith   PetscFunctionBegin;
3814b9ad928SBarry Smith   jac  = (PC_Composite *)pc->data;
3824b9ad928SBarry Smith   next = jac->head;
3834b9ad928SBarry Smith   for (i = 0; i < n; i++) {
38428b400f6SJacob Faibussowitsch     PetscCheck(next->next, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "Not enough PCs in composite preconditioner");
3854b9ad928SBarry Smith     next = next->next;
3864b9ad928SBarry Smith   }
3874b9ad928SBarry Smith   *subpc = next->pc;
3884b9ad928SBarry Smith   PetscFunctionReturn(0);
3894b9ad928SBarry Smith }
3904b9ad928SBarry Smith 
391f39d8e23SSatish Balay /*@
3924b9ad928SBarry Smith    PCCompositeSetType - Sets the type of composite preconditioner.
3934b9ad928SBarry Smith 
394*c3339decSBarry Smith    Logically Collective
3954b9ad928SBarry Smith 
396c60c7ad4SBarry Smith    Input Parameters:
3972a6744ebSBarry Smith +  pc - the preconditioner context
398f1580f4eSBarry Smith -  type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`
3994b9ad928SBarry Smith 
4004b9ad928SBarry Smith    Options Database Key:
4014b9ad928SBarry Smith .  -pc_composite_type <type: one of multiplicative, additive, special> - Sets composite preconditioner type
4024b9ad928SBarry Smith 
403f1580f4eSBarry Smith    Level: advanced
4044b9ad928SBarry Smith 
405f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
406f1580f4eSBarry Smith           `PCCompositeGetType()`
4074b9ad928SBarry Smith @*/
408d71ae5a4SJacob Faibussowitsch PetscErrorCode PCCompositeSetType(PC pc, PCCompositeType type)
409d71ae5a4SJacob Faibussowitsch {
4104b9ad928SBarry Smith   PetscFunctionBegin;
4110700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
412c5eb9154SBarry Smith   PetscValidLogicalCollectiveEnum(pc, type, 2);
413cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeSetType_C", (PC, PCCompositeType), (pc, type));
4144b9ad928SBarry Smith   PetscFunctionReturn(0);
4154b9ad928SBarry Smith }
4164b9ad928SBarry Smith 
417c60c7ad4SBarry Smith /*@
418721f67b5SBarry Smith    PCCompositeGetType - Gets the type of composite preconditioner.
419c60c7ad4SBarry Smith 
420*c3339decSBarry Smith    Logically Collective
421c60c7ad4SBarry Smith 
422c60c7ad4SBarry Smith    Input Parameter:
423c60c7ad4SBarry Smith .  pc - the preconditioner context
424c60c7ad4SBarry Smith 
425c60c7ad4SBarry Smith    Output Parameter:
426f1580f4eSBarry Smith .  type - `PC_COMPOSITE_ADDITIVE` (default), `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`
427c60c7ad4SBarry Smith 
428f1580f4eSBarry Smith    Level: advanced
429c60c7ad4SBarry Smith 
430f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
431f1580f4eSBarry Smith           `PCCompositeSetType()`
432c60c7ad4SBarry Smith @*/
433d71ae5a4SJacob Faibussowitsch PetscErrorCode PCCompositeGetType(PC pc, PCCompositeType *type)
434d71ae5a4SJacob Faibussowitsch {
435c60c7ad4SBarry Smith   PetscFunctionBegin;
436c60c7ad4SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
437cac4c232SBarry Smith   PetscUseMethod(pc, "PCCompositeGetType_C", (PC, PCCompositeType *), (pc, type));
438c60c7ad4SBarry Smith   PetscFunctionReturn(0);
439c60c7ad4SBarry Smith }
440c60c7ad4SBarry Smith 
441f39d8e23SSatish Balay /*@
442f1580f4eSBarry Smith    PCCompositeSpecialSetAlpha - Sets alpha for the special composite preconditioner, `PC_COMPOSITE_SPECIAL`,
4434b9ad928SBarry Smith      for alphaI + R + S
4444b9ad928SBarry Smith 
445*c3339decSBarry Smith    Logically Collective
4464b9ad928SBarry Smith 
447d8d19677SJose E. Roman    Input Parameters:
4484b9ad928SBarry Smith +  pc - the preconditioner context
4494b9ad928SBarry Smith -  alpha - scale on identity
4504b9ad928SBarry Smith 
4514b9ad928SBarry Smith    Level: Developer
4524b9ad928SBarry Smith 
453f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PCCompositeType`,
454f1580f4eSBarry Smith           `PCCompositeSetType()`, `PCCompositeGetType()`
4554b9ad928SBarry Smith @*/
456d71ae5a4SJacob Faibussowitsch PetscErrorCode PCCompositeSpecialSetAlpha(PC pc, PetscScalar alpha)
457d71ae5a4SJacob Faibussowitsch {
4584b9ad928SBarry Smith   PetscFunctionBegin;
4590700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
460c5eb9154SBarry Smith   PetscValidLogicalCollectiveScalar(pc, alpha, 2);
461cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeSpecialSetAlpha_C", (PC, PetscScalar), (pc, alpha));
4624b9ad928SBarry Smith   PetscFunctionReturn(0);
4634b9ad928SBarry Smith }
4644b9ad928SBarry Smith 
4654b9ad928SBarry Smith /*@C
466f1580f4eSBarry Smith   PCCompositeAddPCType - Adds another `PC` of the given type to the composite `PC`.
4674b9ad928SBarry Smith 
468*c3339decSBarry Smith   Collective
4694b9ad928SBarry Smith 
4704b9ad928SBarry Smith   Input Parameters:
4712a6744ebSBarry Smith + pc - the preconditioner context
4722a6744ebSBarry Smith - type - the type of the new preconditioner
4734b9ad928SBarry Smith 
474f1580f4eSBarry Smith   Level: intermediate
4754b9ad928SBarry Smith 
476f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
4774b9ad928SBarry Smith @*/
478d71ae5a4SJacob Faibussowitsch PetscErrorCode PCCompositeAddPCType(PC pc, PCType type)
479d71ae5a4SJacob Faibussowitsch {
4804b9ad928SBarry Smith   PetscFunctionBegin;
4810700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
482cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeAddPCType_C", (PC, PCType), (pc, type));
4838aa07aa6SMatthew G. Knepley   PetscFunctionReturn(0);
4848aa07aa6SMatthew G. Knepley }
4858aa07aa6SMatthew G. Knepley 
4868aa07aa6SMatthew G. Knepley /*@
487f1580f4eSBarry Smith   PCCompositeAddPC - Adds another `PC` to the composite `PC`.
4888aa07aa6SMatthew G. Knepley 
489*c3339decSBarry Smith   Collective
4908aa07aa6SMatthew G. Knepley 
4918aa07aa6SMatthew G. Knepley   Input Parameters:
4928aa07aa6SMatthew G. Knepley + pc    - the preconditioner context
4938aa07aa6SMatthew G. Knepley - subpc - the new preconditioner
4948aa07aa6SMatthew G. Knepley 
495f1580f4eSBarry Smith    Level: intermediate
4968aa07aa6SMatthew G. Knepley 
497f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`
4988aa07aa6SMatthew G. Knepley @*/
499d71ae5a4SJacob Faibussowitsch PetscErrorCode PCCompositeAddPC(PC pc, PC subpc)
500d71ae5a4SJacob Faibussowitsch {
5018aa07aa6SMatthew G. Knepley   PetscFunctionBegin;
5028aa07aa6SMatthew G. Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
5038aa07aa6SMatthew G. Knepley   PetscValidHeaderSpecific(subpc, PC_CLASSID, 2);
504cac4c232SBarry Smith   PetscTryMethod(pc, "PCCompositeAddPC_C", (PC, PC), (pc, subpc));
5054b9ad928SBarry Smith   PetscFunctionReturn(0);
5064b9ad928SBarry Smith }
5074b9ad928SBarry Smith 
5088e6eba06SBarry Smith /*@
509f1580f4eSBarry Smith    PCCompositeGetNumberPC - Gets the number of `PC` objects in the composite `PC`.
5108e6eba06SBarry Smith 
5118e6eba06SBarry Smith    Not Collective
5128e6eba06SBarry Smith 
5138e6eba06SBarry Smith    Input Parameter:
5148e6eba06SBarry Smith .  pc - the preconditioner context
5158e6eba06SBarry Smith 
5168e6eba06SBarry Smith    Output Parameter:
5178e6eba06SBarry Smith .  num - the number of sub pcs
5188e6eba06SBarry Smith 
5198e6eba06SBarry Smith    Level: Developer
5208e6eba06SBarry Smith 
521f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PCCompositeGetPC()`, `PCCompositeAddPC()`, `PCCompositeAddPCType()`
5228e6eba06SBarry Smith @*/
523d71ae5a4SJacob Faibussowitsch PetscErrorCode PCCompositeGetNumberPC(PC pc, PetscInt *num)
524d71ae5a4SJacob Faibussowitsch {
5258e6eba06SBarry Smith   PetscFunctionBegin;
5268e6eba06SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
5278e6eba06SBarry Smith   PetscValidIntPointer(num, 2);
528cac4c232SBarry Smith   PetscUseMethod(pc, "PCCompositeGetNumberPC_C", (PC, PetscInt *), (pc, num));
5298e6eba06SBarry Smith   PetscFunctionReturn(0);
5308e6eba06SBarry Smith }
5318e6eba06SBarry Smith 
532f39d8e23SSatish Balay /*@
533f1580f4eSBarry Smith    PCCompositeGetPC - Gets one of the `PC` objects in the composite `PC`.
5344b9ad928SBarry Smith 
5354b9ad928SBarry Smith    Not Collective
5364b9ad928SBarry Smith 
537d8d19677SJose E. Roman    Input Parameters:
5382a6744ebSBarry Smith +  pc - the preconditioner context
5392a6744ebSBarry Smith -  n - the number of the pc requested
5404b9ad928SBarry Smith 
541f1580f4eSBarry Smith    Output Parameter:
5424b9ad928SBarry Smith .  subpc - the PC requested
5434b9ad928SBarry Smith 
544f1580f4eSBarry Smith    Level: intermediate
5454b9ad928SBarry Smith 
546f1580f4eSBarry Smith     Note:
547f1580f4eSBarry Smith     To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
548f1580f4eSBarry Smith     call `PCSetOperators()` on that `PC`.
5492b1d202aSBarry Smith 
550f1580f4eSBarry Smith .seealso: `PCCOMPOSITE`, `PCCompositeAddPCType()`, `PCCompositeGetNumberPC()`, `PCSetOperators()`
5514b9ad928SBarry Smith @*/
552d71ae5a4SJacob Faibussowitsch PetscErrorCode PCCompositeGetPC(PC pc, PetscInt n, PC *subpc)
553d71ae5a4SJacob Faibussowitsch {
5544b9ad928SBarry Smith   PetscFunctionBegin;
5550700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
5564482741eSBarry Smith   PetscValidPointer(subpc, 3);
557cac4c232SBarry Smith   PetscUseMethod(pc, "PCCompositeGetPC_C", (PC, PetscInt, PC *), (pc, n, subpc));
5584b9ad928SBarry Smith   PetscFunctionReturn(0);
5594b9ad928SBarry Smith }
5604b9ad928SBarry Smith 
5614b9ad928SBarry Smith /*MC
5624b9ad928SBarry Smith      PCCOMPOSITE - Build a preconditioner by composing together several preconditioners
5634b9ad928SBarry Smith 
5644b9ad928SBarry Smith    Options Database Keys:
5652eab2d5bSJungho Lee +  -pc_composite_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets composite preconditioner type
566f1580f4eSBarry Smith .  -pc_use_amat - activates `PCSetUseAmat()`
56751f519a2SBarry Smith -  -pc_composite_pcs - <pc0,pc1,...> list of PCs to compose
5684b9ad928SBarry Smith 
5694b9ad928SBarry Smith    Level: intermediate
5704b9ad928SBarry Smith 
57195452b02SPatrick Sanan    Notes:
572f1580f4eSBarry Smith    To use a Krylov method inside the composite preconditioner, set the `PCType` of one or more
573f1580f4eSBarry Smith    inner `PC`s to be `PCKSP`. Using a Krylov method inside another Krylov method can be dangerous (you get divergence or
574f1580f4eSBarry Smith    the incorrect answer) unless you use `KSPFGMRES` as the outer Krylov method
575f1580f4eSBarry Smith 
576f1580f4eSBarry Smith    To use a different operator to construct one of the inner preconditioners first call `PCCompositeGetPC()`, then
577f1580f4eSBarry Smith    call `PCSetOperators()` on that `PC`.
5784b9ad928SBarry Smith 
579db781477SPatrick Sanan .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`,
580db781477SPatrick Sanan           `PCSHELL`, `PCKSP`, `PCCompositeSetType()`, `PCCompositeSpecialSetAlpha()`, `PCCompositeAddPCType()`,
581f1580f4eSBarry Smith           `PCCompositeGetPC()`, `PCSetUseAmat()`, `PCCompositeAddPC()`, `PCCompositeGetNumberPC()`
5824b9ad928SBarry Smith M*/
5834b9ad928SBarry Smith 
584d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_Composite(PC pc)
585d71ae5a4SJacob Faibussowitsch {
5864b9ad928SBarry Smith   PC_Composite *jac;
5874b9ad928SBarry Smith 
5884b9ad928SBarry Smith   PetscFunctionBegin;
5894dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&jac));
5902fa5cd67SKarl Rupp 
5914b9ad928SBarry Smith   pc->ops->apply           = PCApply_Composite_Additive;
5922533e041SBarry Smith   pc->ops->applytranspose  = PCApplyTranspose_Composite_Additive;
5934b9ad928SBarry Smith   pc->ops->setup           = PCSetUp_Composite;
59469d2c0f9SBarry Smith   pc->ops->reset           = PCReset_Composite;
5954b9ad928SBarry Smith   pc->ops->destroy         = PCDestroy_Composite;
5964b9ad928SBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_Composite;
5974b9ad928SBarry Smith   pc->ops->view            = PCView_Composite;
5980a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
5994b9ad928SBarry Smith 
6004b9ad928SBarry Smith   pc->data   = (void *)jac;
6014b9ad928SBarry Smith   jac->type  = PC_COMPOSITE_ADDITIVE;
6020a545947SLisandro Dalcin   jac->work1 = NULL;
6030a545947SLisandro Dalcin   jac->work2 = NULL;
6040a545947SLisandro Dalcin   jac->head  = NULL;
6054b9ad928SBarry Smith 
6069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSetType_C", PCCompositeSetType_Composite));
6079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetType_C", PCCompositeGetType_Composite));
6089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPCType_C", PCCompositeAddPCType_Composite));
6099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeAddPC_C", PCCompositeAddPC_Composite));
6109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetNumberPC_C", PCCompositeGetNumberPC_Composite));
6119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeGetPC_C", PCCompositeGetPC_Composite));
6129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCCompositeSpecialSetAlpha_C", PCCompositeSpecialSetAlpha_Composite));
6134b9ad928SBarry Smith   PetscFunctionReturn(0);
6144b9ad928SBarry Smith }
615