xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision 3220ff8572602716d60bdda8b51773ebceb3c8ea)
1af0996ceSBarry Smith #include <petsc/private/pcimpl.h>  /*I "petscpc.h" I*/
2a80b646eSBarry Smith #include <petsc/private/kspimpl.h> /*  This is needed to provide the appropriate PETSC_EXTERN for KSP_Solve_FS ....*/
3d484b384SBoris Martin #include <petsc/private/matimpl.h> /* MatScatterDense_Private() for PCMatApply() */
41e25c274SJed Brown #include <petscdm.h>
5f7cbcdf3SPierre Jolivet #include <petscdevice.h>
6f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_CUDA)
7f7cbcdf3SPierre Jolivet   #include <petscdevice_cuda.h>
8f7cbcdf3SPierre Jolivet #endif
9f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_HIP)
10f7cbcdf3SPierre Jolivet   #include <petscdevice_hip.h>
11f7cbcdf3SPierre Jolivet #endif
120971522cSBarry Smith 
130a545947SLisandro Dalcin const char *const PCFieldSplitSchurPreTypes[]  = {"SELF", "SELFP", "A11", "USER", "FULL", "PCFieldSplitSchurPreType", "PC_FIELDSPLIT_SCHUR_PRE_", NULL};
140a545947SLisandro Dalcin const char *const PCFieldSplitSchurFactTypes[] = {"DIAG", "LOWER", "UPPER", "FULL", "PCFieldSplitSchurFactType", "PC_FIELDSPLIT_SCHUR_FACT_", NULL};
15c5d2311dSJed Brown 
169df09d43SBarry Smith PetscLogEvent KSP_Solve_FS_0, KSP_Solve_FS_1, KSP_Solve_FS_S, KSP_Solve_FS_U, KSP_Solve_FS_L, KSP_Solve_FS_2, KSP_Solve_FS_3, KSP_Solve_FS_4;
179df09d43SBarry Smith 
180971522cSBarry Smith typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
190971522cSBarry Smith struct _PC_FieldSplitLink {
2069a612a9SBarry Smith   KSP               ksp;
21443836d0SMatthew G Knepley   Vec               x, y, z;
22f5b94327SPierre Jolivet   Mat               X, Y, Z;
23db4c96c1SJed Brown   char             *splitname;
240971522cSBarry Smith   PetscInt          nfields;
255d4c12cdSJungho Lee   PetscInt         *fields, *fields_col;
261b9fc7fcSBarry Smith   VecScatter        sctx;
27f5f0d762SBarry Smith   IS                is, is_col;
2851f519a2SBarry Smith   PC_FieldSplitLink next, previous;
299df09d43SBarry Smith   PetscLogEvent     event;
305ddf11f8SNicolas Barnafi 
315ddf11f8SNicolas Barnafi   /* Used only when setting coordinates with PCSetCoordinates */
325ddf11f8SNicolas Barnafi   PetscInt   dim;
335ddf11f8SNicolas Barnafi   PetscInt   ndofs;
345ddf11f8SNicolas Barnafi   PetscReal *coords;
350971522cSBarry Smith };
360971522cSBarry Smith 
370971522cSBarry Smith typedef struct {
3868dd23aaSBarry Smith   PCCompositeType type;
39ace3abfcSBarry Smith   PetscBool       defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
40ace3abfcSBarry Smith   PetscBool       splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */
4130ad9308SMatthew Knepley   PetscInt        bs;           /* Block size for IS and Mat structures */
4230ad9308SMatthew Knepley   PetscInt        nsplits;      /* Number of field divisions defined */
4379416396SBarry Smith   Vec            *x, *y, w1, w2;
44519d70e2SJed Brown   Mat            *mat;    /* The diagonal block for each split */
45519d70e2SJed Brown   Mat            *pmat;   /* The preconditioning diagonal block for each split */
4630ad9308SMatthew Knepley   Mat            *Afield; /* The rows of the matrix associated with each split */
47ace3abfcSBarry Smith   PetscBool       issetup;
482fa5cd67SKarl Rupp 
4930ad9308SMatthew Knepley   /* Only used when Schur complement preconditioning is used */
5030ad9308SMatthew Knepley   Mat                       B;          /* The (0,1) block */
5130ad9308SMatthew Knepley   Mat                       C;          /* The (1,0) block */
52443836d0SMatthew G Knepley   Mat                       schur;      /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */
537addb90fSBarry Smith   Mat                       schurp;     /* Assembled approximation to S built by MatSchurComplement to be used as a matrix for constructing the preconditioner when solving with S */
547addb90fSBarry Smith   Mat                       schur_user; /* User-provided matrix for constructing the preconditioner for the Schur complement */
557addb90fSBarry Smith   PCFieldSplitSchurPreType  schurpre;   /* Determines which matrix is used for the Schur complement */
56c9c6ffaaSJed Brown   PCFieldSplitSchurFactType schurfactorization;
5730ad9308SMatthew Knepley   KSP                       kspschur;   /* The solver for S */
58443836d0SMatthew G Knepley   KSP                       kspupper;   /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */
59c096484dSStefano Zampini   PetscScalar               schurscale; /* Scaling factor for the Schur complement solution with DIAG factorization */
60c096484dSStefano Zampini 
61a51937d4SCarola Kruse   /* Only used when Golub-Kahan bidiagonalization preconditioning is used */
62a51937d4SCarola Kruse   Mat          H;           /* The modified matrix H = A00 + nu*A01*A01'              */
63a51937d4SCarola Kruse   PetscReal    gkbtol;      /* Stopping tolerance for lower bound estimate            */
64a51937d4SCarola Kruse   PetscInt     gkbdelay;    /* The delay window for the stopping criterion            */
65a51937d4SCarola Kruse   PetscReal    gkbnu;       /* Parameter for augmented Lagrangian H = A + nu*A01*A01' */
66a51937d4SCarola Kruse   PetscInt     gkbmaxit;    /* Maximum number of iterations for outer loop            */
67de482cd7SCarola Kruse   PetscBool    gkbmonitor;  /* Monitor for gkb iterations and the lower bound error   */
68de482cd7SCarola Kruse   PetscViewer  gkbviewer;   /* Viewer context for gkbmonitor                          */
69e071a0a4SCarola Kruse   Vec          u, v, d, Hu; /* Work vectors for the GKB algorithm                     */
70e071a0a4SCarola Kruse   PetscScalar *vecz;        /* Contains intermediate values, eg for lower bound       */
71a51937d4SCarola Kruse 
7297bbdb24SBarry Smith   PC_FieldSplitLink head;
736dbb499eSCian Wilson   PetscBool         isrestrict;       /* indicates PCFieldSplitRestrictIS() has been last called on this object, hack */
74c1570756SJed Brown   PetscBool         suboptionsset;    /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */
754ab8060aSDmitry Karpeev   PetscBool         dm_splits;        /* Whether to use DMCreateFieldDecomposition() whenever possible */
76c84da90fSDmitry Karpeev   PetscBool         diag_use_amat;    /* Whether to extract diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */
77c84da90fSDmitry Karpeev   PetscBool         offdiag_use_amat; /* Whether to extract off-diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */
787b752e3dSPatrick Sanan   PetscBool         detect;           /* Whether to form 2-way split by finding zero diagonal entries */
795ddf11f8SNicolas Barnafi   PetscBool         coordinates_set;  /* Whether PCSetCoordinates has been called */
800971522cSBarry Smith } PC_FieldSplit;
810971522cSBarry Smith 
8216913363SBarry Smith /*
83f1580f4eSBarry Smith     Note:
8495452b02SPatrick Sanan     there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
8516913363SBarry Smith    inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
8616913363SBarry Smith    PC you could change this.
8716913363SBarry Smith */
88084e4875SJed Brown 
897addb90fSBarry Smith /* This helper is so that setting a user-provided matrix is orthogonal to choosing to use it.  This way the
90084e4875SJed Brown * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
FieldSplitSchurPre(PC_FieldSplit * jac)91d71ae5a4SJacob Faibussowitsch static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
92d71ae5a4SJacob Faibussowitsch {
93084e4875SJed Brown   switch (jac->schurpre) {
94d71ae5a4SJacob Faibussowitsch   case PC_FIELDSPLIT_SCHUR_PRE_SELF:
95d71ae5a4SJacob Faibussowitsch     return jac->schur;
96d71ae5a4SJacob Faibussowitsch   case PC_FIELDSPLIT_SCHUR_PRE_SELFP:
97d71ae5a4SJacob Faibussowitsch     return jac->schurp;
98d71ae5a4SJacob Faibussowitsch   case PC_FIELDSPLIT_SCHUR_PRE_A11:
99d71ae5a4SJacob Faibussowitsch     return jac->pmat[1];
100e74569cdSMatthew G. Knepley   case PC_FIELDSPLIT_SCHUR_PRE_FULL: /* We calculate this and store it in schur_user */
101084e4875SJed Brown   case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
102d71ae5a4SJacob Faibussowitsch   default:
103d71ae5a4SJacob Faibussowitsch     return jac->schur_user ? jac->schur_user : jac->pmat[1];
104084e4875SJed Brown   }
105084e4875SJed Brown }
106084e4875SJed Brown 
1079804daf3SBarry Smith #include <petscdraw.h>
PCView_FieldSplit(PC pc,PetscViewer viewer)108d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_FieldSplit(PC pc, PetscViewer viewer)
109d71ae5a4SJacob Faibussowitsch {
1100971522cSBarry Smith   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
1119f196a02SMartin Diehl   PetscBool         isascii, isdraw;
1120971522cSBarry Smith   PetscInt          i, j;
1135a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
1140971522cSBarry Smith 
1150971522cSBarry Smith   PetscFunctionBegin;
1169f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1179566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1189f196a02SMartin Diehl   if (isascii) {
1192c9966d7SBarry Smith     if (jac->bs > 0) {
12063a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with %s composition: total splits = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits, jac->bs));
1212c9966d7SBarry Smith     } else {
12263a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with %s composition: total splits = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits));
1232c9966d7SBarry Smith     }
12448a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for blocks\n"));
12548a46eb9SPierre Jolivet     if (jac->diag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for diagonal blocks\n"));
12648a46eb9SPierre Jolivet     if (jac->offdiag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for off-diagonal blocks\n"));
1279566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Solver info for each split is in the following KSP objects:\n"));
1280971522cSBarry Smith     for (i = 0; i < jac->nsplits; i++) {
1291ab39975SBarry Smith       if (ilink->fields) {
13063a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Fields ", i));
1319566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
1325a9f2f41SSatish Balay         for (j = 0; j < ilink->nfields; j++) {
13348a46eb9SPierre Jolivet           if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
13463a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
1350971522cSBarry Smith         }
1369566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
1379566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
1381ab39975SBarry Smith       } else {
13963a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Defined by IS\n", i));
1401ab39975SBarry Smith       }
1419566063dSJacob Faibussowitsch       PetscCall(KSPView(ilink->ksp, viewer));
1425a9f2f41SSatish Balay       ilink = ilink->next;
1430971522cSBarry Smith     }
1442fa5cd67SKarl Rupp   }
1452fa5cd67SKarl Rupp 
1462fa5cd67SKarl Rupp   if (isdraw) {
147d9884438SBarry Smith     PetscDraw draw;
148d9884438SBarry Smith     PetscReal x, y, w, wd;
149d9884438SBarry Smith 
1509566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
1519566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
152d9884438SBarry Smith     w  = 2 * PetscMin(1.0 - x, x);
153d9884438SBarry Smith     wd = w / (jac->nsplits + 1);
154d9884438SBarry Smith     x  = x - wd * (jac->nsplits - 1) / 2.0;
155d9884438SBarry Smith     for (i = 0; i < jac->nsplits; i++) {
1569566063dSJacob Faibussowitsch       PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
1579566063dSJacob Faibussowitsch       PetscCall(KSPView(ilink->ksp, viewer));
1589566063dSJacob Faibussowitsch       PetscCall(PetscDrawPopCurrentPoint(draw));
159d9884438SBarry Smith       x += wd;
160d9884438SBarry Smith       ilink = ilink->next;
161d9884438SBarry Smith     }
1620971522cSBarry Smith   }
1633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1640971522cSBarry Smith }
1650971522cSBarry Smith 
PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)166d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_FieldSplit_Schur(PC pc, PetscViewer viewer)
167d71ae5a4SJacob Faibussowitsch {
1683b224e63SBarry Smith   PC_FieldSplit             *jac = (PC_FieldSplit *)pc->data;
1699f196a02SMartin Diehl   PetscBool                  isascii, isdraw;
1703b224e63SBarry Smith   PetscInt                   i, j;
1713b224e63SBarry Smith   PC_FieldSplitLink          ilink = jac->head;
172a9908d51SBarry Smith   MatSchurComplementAinvType atype;
1733b224e63SBarry Smith 
1743b224e63SBarry Smith   PetscFunctionBegin;
1759f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
1769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
1779f196a02SMartin Diehl   if (isascii) {
1782c9966d7SBarry Smith     if (jac->bs > 0) {
17963a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with Schur preconditioner, blocksize = %" PetscInt_FMT ", factorization %s\n", jac->bs, PCFieldSplitSchurFactTypes[jac->schurfactorization]));
1802c9966d7SBarry Smith     } else {
1819566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with Schur preconditioner, factorization %s\n", PCFieldSplitSchurFactTypes[jac->schurfactorization]));
1822c9966d7SBarry Smith     }
18348a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for blocks\n"));
1843e8b8b31SMatthew G Knepley     switch (jac->schurpre) {
185d71ae5a4SJacob Faibussowitsch     case PC_FIELDSPLIT_SCHUR_PRE_SELF:
186d71ae5a4SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from S itself\n"));
187d71ae5a4SJacob Faibussowitsch       break;
188a7476a74SDmitry Karpeev     case PC_FIELDSPLIT_SCHUR_PRE_SELFP:
1897cf5f706SPierre Jolivet       if (jac->schur) {
1909566063dSJacob Faibussowitsch         PetscCall(MatSchurComplementGetAinvType(jac->schur, &atype));
1919371c9d4SSatish Balay         PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from Sp, an assembled approximation to S, which uses A00's %sinverse\n", atype == MAT_SCHUR_COMPLEMENT_AINV_DIAG ? "diagonal's " : (atype == MAT_SCHUR_COMPLEMENT_AINV_BLOCK_DIAG ? "block diagonal's " : (atype == MAT_SCHUR_COMPLEMENT_AINV_FULL ? "full " : "lumped diagonal's "))));
1927cf5f706SPierre Jolivet       }
193a9908d51SBarry Smith       break;
194d71ae5a4SJacob Faibussowitsch     case PC_FIELDSPLIT_SCHUR_PRE_A11:
195d71ae5a4SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from A11\n"));
196d71ae5a4SJacob Faibussowitsch       break;
197d71ae5a4SJacob Faibussowitsch     case PC_FIELDSPLIT_SCHUR_PRE_FULL:
198d71ae5a4SJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from the exact Schur complement\n"));
199d71ae5a4SJacob Faibussowitsch       break;
2003e8b8b31SMatthew G Knepley     case PC_FIELDSPLIT_SCHUR_PRE_USER:
2013e8b8b31SMatthew G Knepley       if (jac->schur_user) {
2029566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from user provided matrix\n"));
2033e8b8b31SMatthew G Knepley       } else {
2049566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from A11\n"));
2053e8b8b31SMatthew G Knepley       }
2063e8b8b31SMatthew G Knepley       break;
207d71ae5a4SJacob Faibussowitsch     default:
208d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre);
2093e8b8b31SMatthew G Knepley     }
2109566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Split info:\n"));
2119566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
2123b224e63SBarry Smith     for (i = 0; i < jac->nsplits; i++) {
2133b224e63SBarry Smith       if (ilink->fields) {
21463a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Fields ", i));
2159566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
2163b224e63SBarry Smith         for (j = 0; j < ilink->nfields; j++) {
21748a46eb9SPierre Jolivet           if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
21863a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
2193b224e63SBarry Smith         }
2209566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
2219566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
2223b224e63SBarry Smith       } else {
22363a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Defined by IS\n", i));
2243b224e63SBarry Smith       }
2253b224e63SBarry Smith       ilink = ilink->next;
2263b224e63SBarry Smith     }
2279566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for A00 block\n"));
2289566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
229ac530a7eSPierre Jolivet     if (jac->head) PetscCall(KSPView(jac->head->ksp, viewer));
230ac530a7eSPierre Jolivet     else PetscCall(PetscViewerASCIIPrintf(viewer, "  not yet available\n"));
2319566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
23206de4afeSJed Brown     if (jac->head && jac->kspupper != jac->head->ksp) {
2339566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for upper A00 in upper triangular factor\n"));
2349566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPushTab(viewer));
2359566063dSJacob Faibussowitsch       if (jac->kspupper) PetscCall(KSPView(jac->kspupper, viewer));
2369566063dSJacob Faibussowitsch       else PetscCall(PetscViewerASCIIPrintf(viewer, "  not yet available\n"));
2379566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPopTab(viewer));
238443836d0SMatthew G Knepley     }
2399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for S = A11 - A10 inv(A00) A01\n"));
2409566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
24112cae6f2SJed Brown     if (jac->kspschur) {
2429566063dSJacob Faibussowitsch       PetscCall(KSPView(jac->kspschur, viewer));
24312cae6f2SJed Brown     } else {
2449566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  not yet available\n"));
24512cae6f2SJed Brown     }
2469566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
2479566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
24806de4afeSJed Brown   } else if (isdraw && jac->head) {
2494996c5bdSBarry Smith     PetscDraw draw;
2504996c5bdSBarry Smith     PetscReal x, y, w, wd, h;
2514996c5bdSBarry Smith     PetscInt  cnt = 2;
2524996c5bdSBarry Smith     char      str[32];
2534996c5bdSBarry Smith 
2549566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
2559566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
256c74581afSBarry Smith     if (jac->kspupper != jac->head->ksp) cnt++;
257c74581afSBarry Smith     w  = 2 * PetscMin(1.0 - x, x);
258c74581afSBarry Smith     wd = w / (cnt + 1);
259c74581afSBarry Smith 
2609566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(str, 32, "Schur fact. %s", PCFieldSplitSchurFactTypes[jac->schurfactorization]));
2619566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
2624996c5bdSBarry Smith     y -= h;
2634996c5bdSBarry Smith     if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER && !jac->schur_user) {
2649566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(str, 32, "Prec. for Schur from %s", PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11]));
2653b224e63SBarry Smith     } else {
2669566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(str, 32, "Prec. for Schur from %s", PCFieldSplitSchurPreTypes[jac->schurpre]));
2674996c5bdSBarry Smith     }
2689566063dSJacob Faibussowitsch     PetscCall(PetscDrawStringBoxed(draw, x + wd * (cnt - 1) / 2.0, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
2694996c5bdSBarry Smith     y -= h;
2704996c5bdSBarry Smith     x = x - wd * (cnt - 1) / 2.0;
2714996c5bdSBarry Smith 
2729566063dSJacob Faibussowitsch     PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
2739566063dSJacob Faibussowitsch     PetscCall(KSPView(jac->head->ksp, viewer));
2749566063dSJacob Faibussowitsch     PetscCall(PetscDrawPopCurrentPoint(draw));
2754996c5bdSBarry Smith     if (jac->kspupper != jac->head->ksp) {
2764996c5bdSBarry Smith       x += wd;
2779566063dSJacob Faibussowitsch       PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
2789566063dSJacob Faibussowitsch       PetscCall(KSPView(jac->kspupper, viewer));
2799566063dSJacob Faibussowitsch       PetscCall(PetscDrawPopCurrentPoint(draw));
2804996c5bdSBarry Smith     }
2814996c5bdSBarry Smith     x += wd;
2829566063dSJacob Faibussowitsch     PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
2839566063dSJacob Faibussowitsch     PetscCall(KSPView(jac->kspschur, viewer));
2849566063dSJacob Faibussowitsch     PetscCall(PetscDrawPopCurrentPoint(draw));
2853b224e63SBarry Smith   }
2863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2873b224e63SBarry Smith }
2883b224e63SBarry Smith 
PCView_FieldSplit_GKB(PC pc,PetscViewer viewer)289d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCView_FieldSplit_GKB(PC pc, PetscViewer viewer)
290d71ae5a4SJacob Faibussowitsch {
291a51937d4SCarola Kruse   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
2929f196a02SMartin Diehl   PetscBool         isascii, isdraw;
293a51937d4SCarola Kruse   PetscInt          i, j;
294a51937d4SCarola Kruse   PC_FieldSplitLink ilink = jac->head;
295a51937d4SCarola Kruse 
296a51937d4SCarola Kruse   PetscFunctionBegin;
2979f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
2989566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
2999f196a02SMartin Diehl   if (isascii) {
300a51937d4SCarola Kruse     if (jac->bs > 0) {
30163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with %s composition: total splits = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits, jac->bs));
302a51937d4SCarola Kruse     } else {
30363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with %s composition: total splits = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits));
304a51937d4SCarola Kruse     }
30548a46eb9SPierre Jolivet     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for blocks\n"));
30648a46eb9SPierre Jolivet     if (jac->diag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for diagonal blocks\n"));
30748a46eb9SPierre Jolivet     if (jac->offdiag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for off-diagonal blocks\n"));
308a51937d4SCarola Kruse 
30963a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Stopping tolerance=%.1e, delay in error estimate=%" PetscInt_FMT ", maximum iterations=%" PetscInt_FMT "\n", (double)jac->gkbtol, jac->gkbdelay, jac->gkbmaxit));
3109566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Solver info for H = A00 + nu*A01*A01' matrix:\n"));
3119566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
312a51937d4SCarola Kruse 
313a51937d4SCarola Kruse     if (ilink->fields) {
31463a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Split number 0 Fields "));
3159566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
316a51937d4SCarola Kruse       for (j = 0; j < ilink->nfields; j++) {
31748a46eb9SPierre Jolivet         if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
31863a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
319a51937d4SCarola Kruse       }
3209566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
3219566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
322a51937d4SCarola Kruse     } else {
32363a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Split number 0 Defined by IS\n"));
324a51937d4SCarola Kruse     }
3259566063dSJacob Faibussowitsch     PetscCall(KSPView(ilink->ksp, viewer));
326a51937d4SCarola Kruse 
3279566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
328a51937d4SCarola Kruse   }
329a51937d4SCarola Kruse 
330a51937d4SCarola Kruse   if (isdraw) {
331a51937d4SCarola Kruse     PetscDraw draw;
332a51937d4SCarola Kruse     PetscReal x, y, w, wd;
333a51937d4SCarola Kruse 
3349566063dSJacob Faibussowitsch     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
3359566063dSJacob Faibussowitsch     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
336a51937d4SCarola Kruse     w  = 2 * PetscMin(1.0 - x, x);
337a51937d4SCarola Kruse     wd = w / (jac->nsplits + 1);
338a51937d4SCarola Kruse     x  = x - wd * (jac->nsplits - 1) / 2.0;
339a51937d4SCarola Kruse     for (i = 0; i < jac->nsplits; i++) {
3409566063dSJacob Faibussowitsch       PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
3419566063dSJacob Faibussowitsch       PetscCall(KSPView(ilink->ksp, viewer));
3429566063dSJacob Faibussowitsch       PetscCall(PetscDrawPopCurrentPoint(draw));
343a51937d4SCarola Kruse       x += wd;
344a51937d4SCarola Kruse       ilink = ilink->next;
345a51937d4SCarola Kruse     }
346a51937d4SCarola Kruse   }
3473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
348a51937d4SCarola Kruse }
349a51937d4SCarola Kruse 
35080670ca5SBarry Smith /* Precondition: jac->bs is set to a meaningful value or MATNEST */
PCFieldSplitSetRuntimeSplits_Private(PC pc)351d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc)
352d71ae5a4SJacob Faibussowitsch {
3536c924f48SJed Brown   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35480670ca5SBarry Smith   PetscInt       bs, i, nfields, *ifields, nfields_col, *ifields_col;
35580670ca5SBarry Smith   PetscBool      flg, flg_col, mnest;
3565d4c12cdSJungho Lee   char           optionname[128], splitname[8], optionname_col[128];
3576c924f48SJed Brown 
3586c924f48SJed Brown   PetscFunctionBegin;
35980670ca5SBarry Smith   PetscCall(PetscObjectTypeCompare((PetscObject)pc->mat, MATNEST, &mnest));
36080670ca5SBarry Smith   if (mnest) {
36180670ca5SBarry Smith     PetscCall(MatNestGetSize(pc->pmat, &bs, NULL));
36280670ca5SBarry Smith   } else {
36380670ca5SBarry Smith     bs = jac->bs;
36480670ca5SBarry Smith   }
36580670ca5SBarry Smith   PetscCall(PetscMalloc2(bs, &ifields, bs, &ifields_col));
3666c924f48SJed Brown   for (i = 0, flg = PETSC_TRUE;; i++) {
36763a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
36863a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%" PetscInt_FMT "_fields", i));
36963a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(optionname_col, sizeof(optionname_col), "-pc_fieldsplit_%" PetscInt_FMT "_fields_col", i));
37080670ca5SBarry Smith     nfields     = bs;
37180670ca5SBarry Smith     nfields_col = bs;
3729566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg));
3739566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname_col, ifields_col, &nfields_col, &flg_col));
3746c924f48SJed Brown     if (!flg) break;
3755d4c12cdSJungho Lee     else if (flg && !flg_col) {
37628b400f6SJacob Faibussowitsch       PetscCheck(nfields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields");
3779566063dSJacob Faibussowitsch       PetscCall(PCFieldSplitSetFields(pc, splitname, nfields, ifields, ifields));
3782fa5cd67SKarl Rupp     } else {
3797827d75bSBarry Smith       PetscCheck(nfields && nfields_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields");
38008401ef6SPierre Jolivet       PetscCheck(nfields == nfields_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Number of row and column fields must match");
3819566063dSJacob Faibussowitsch       PetscCall(PCFieldSplitSetFields(pc, splitname, nfields, ifields, ifields_col));
3825d4c12cdSJungho Lee     }
3836c924f48SJed Brown   }
3846c924f48SJed Brown   if (i > 0) {
3856c924f48SJed Brown     /* Makes command-line setting of splits take precedence over setting them in code.
3866c924f48SJed Brown        Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would
3876c924f48SJed Brown        create new splits, which would probably not be what the user wanted. */
3886c924f48SJed Brown     jac->splitdefined = PETSC_TRUE;
3896c924f48SJed Brown   }
39080670ca5SBarry Smith   PetscCall(PetscFree2(ifields, ifields_col));
3913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3926c924f48SJed Brown }
3936c924f48SJed Brown 
PCFieldSplitSetDefaults(PC pc)394d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
395d71ae5a4SJacob Faibussowitsch {
3960971522cSBarry Smith   PC_FieldSplit    *jac                = (PC_FieldSplit *)pc->data;
3975a9f2f41SSatish Balay   PC_FieldSplitLink ilink              = jac->head;
3987b752e3dSPatrick Sanan   PetscBool         fieldsplit_default = PETSC_FALSE, coupling = PETSC_FALSE;
3996c924f48SJed Brown   PetscInt          i;
4000971522cSBarry Smith 
4010971522cSBarry Smith   PetscFunctionBegin;
4027287d2a3SDmitry Karpeev   /*
403f5f0d762SBarry Smith    Kinda messy, but at least this now uses DMCreateFieldDecomposition().
4047287d2a3SDmitry Karpeev    Should probably be rewritten.
4057287d2a3SDmitry Karpeev    */
406f5f0d762SBarry Smith   if (!ilink) {
4079566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_detect_coupling", &coupling, NULL));
4087b752e3dSPatrick Sanan     if (pc->dm && jac->dm_splits && !jac->detect && !coupling) {
409bafc1b83SMatthew G Knepley       PetscInt  numFields, f, i, j;
4100784a22cSJed Brown       char    **fieldNames;
4117b62db95SJungho Lee       IS       *fields;
412e7c4fc90SDmitry Karpeev       DM       *dms;
413bafc1b83SMatthew G Knepley       DM        subdm[128];
414bafc1b83SMatthew G Knepley       PetscBool flg;
415bafc1b83SMatthew G Knepley 
4169566063dSJacob Faibussowitsch       PetscCall(DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms));
417bafc1b83SMatthew G Knepley       /* Allow the user to prescribe the splits */
418bafc1b83SMatthew G Knepley       for (i = 0, flg = PETSC_TRUE;; i++) {
419bafc1b83SMatthew G Knepley         PetscInt ifields[128];
420bafc1b83SMatthew G Knepley         IS       compField;
421bafc1b83SMatthew G Knepley         char     optionname[128], splitname[8];
422bafc1b83SMatthew G Knepley         PetscInt nfields = numFields;
423bafc1b83SMatthew G Knepley 
42463a3b9bcSJacob Faibussowitsch         PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%" PetscInt_FMT "_fields", i));
4259566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg));
426bafc1b83SMatthew G Knepley         if (!flg) break;
42763a3b9bcSJacob Faibussowitsch         PetscCheck(numFields <= 128, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Cannot currently support %" PetscInt_FMT " > 128 fields", numFields);
4289566063dSJacob Faibussowitsch         PetscCall(DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i]));
429bafc1b83SMatthew G Knepley         if (nfields == 1) {
4309566063dSJacob Faibussowitsch           PetscCall(PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField));
431bafc1b83SMatthew G Knepley         } else {
43263a3b9bcSJacob Faibussowitsch           PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
4339566063dSJacob Faibussowitsch           PetscCall(PCFieldSplitSetIS(pc, splitname, compField));
4347287d2a3SDmitry Karpeev         }
4359566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&compField));
436bafc1b83SMatthew G Knepley         for (j = 0; j < nfields; ++j) {
437bafc1b83SMatthew G Knepley           f = ifields[j];
4389566063dSJacob Faibussowitsch           PetscCall(PetscFree(fieldNames[f]));
4399566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[f]));
4407b62db95SJungho Lee         }
441bafc1b83SMatthew G Knepley       }
442bafc1b83SMatthew G Knepley       if (i == 0) {
443bafc1b83SMatthew G Knepley         for (f = 0; f < numFields; ++f) {
4449566063dSJacob Faibussowitsch           PetscCall(PCFieldSplitSetIS(pc, fieldNames[f], fields[f]));
4459566063dSJacob Faibussowitsch           PetscCall(PetscFree(fieldNames[f]));
4469566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[f]));
447bafc1b83SMatthew G Knepley         }
448bafc1b83SMatthew G Knepley       } else {
44948a46eb9SPierre Jolivet         for (j = 0; j < numFields; j++) PetscCall(DMDestroy(dms + j));
4509566063dSJacob Faibussowitsch         PetscCall(PetscFree(dms));
4519566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(i, &dms));
4522fa5cd67SKarl Rupp         for (j = 0; j < i; ++j) dms[j] = subdm[j];
453bafc1b83SMatthew G Knepley       }
4549566063dSJacob Faibussowitsch       PetscCall(PetscFree(fieldNames));
4559566063dSJacob Faibussowitsch       PetscCall(PetscFree(fields));
456e7c4fc90SDmitry Karpeev       if (dms) {
4579566063dSJacob Faibussowitsch         PetscCall(PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n"));
458bafc1b83SMatthew G Knepley         for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) {
4597287d2a3SDmitry Karpeev           const char *prefix;
460f4f49eeaSPierre Jolivet           PetscCall(PetscObjectGetOptionsPrefix((PetscObject)ilink->ksp, &prefix));
461f4f49eeaSPierre Jolivet           PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dms[i], prefix));
4629566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(ilink->ksp, dms[i]));
463*bf0c7fc2SBarry Smith           PetscCall(KSPSetDMActive(ilink->ksp, KSP_DMACTIVE_ALL, PETSC_FALSE));
4649566063dSJacob Faibussowitsch           PetscCall(PetscObjectIncrementTabLevel((PetscObject)dms[i], (PetscObject)ilink->ksp, 0));
4659566063dSJacob Faibussowitsch           PetscCall(DMDestroy(&dms[i]));
4662fa5ba8aSJed Brown         }
4679566063dSJacob Faibussowitsch         PetscCall(PetscFree(dms));
4688b8307b2SJed Brown       }
46966ffff09SJed Brown     } else {
470521d7252SBarry Smith       if (jac->bs <= 0) {
471ac530a7eSPierre Jolivet         if (pc->pmat) PetscCall(MatGetBlockSize(pc->pmat, &jac->bs));
472ac530a7eSPierre Jolivet         else jac->bs = 1;
473521d7252SBarry Smith       }
474d32f9abdSBarry Smith 
4757b752e3dSPatrick Sanan       if (jac->detect) {
4766ce1633cSBarry Smith         IS       zerodiags, rest;
4776ce1633cSBarry Smith         PetscInt nmin, nmax;
4786ce1633cSBarry Smith 
4799566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
4807199da05SBarry Smith         if (jac->diag_use_amat) {
4819566063dSJacob Faibussowitsch           PetscCall(MatFindZeroDiagonals(pc->mat, &zerodiags));
4827199da05SBarry Smith         } else {
4839566063dSJacob Faibussowitsch           PetscCall(MatFindZeroDiagonals(pc->pmat, &zerodiags));
4847199da05SBarry Smith         }
4859566063dSJacob Faibussowitsch         PetscCall(ISComplement(zerodiags, nmin, nmax, &rest));
4869566063dSJacob Faibussowitsch         PetscCall(PCFieldSplitSetIS(pc, "0", rest));
4879566063dSJacob Faibussowitsch         PetscCall(PCFieldSplitSetIS(pc, "1", zerodiags));
4889566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&zerodiags));
4899566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rest));
4903a062f41SBarry Smith       } else if (coupling) {
4913a062f41SBarry Smith         IS       coupling, rest;
4923a062f41SBarry Smith         PetscInt nmin, nmax;
4933a062f41SBarry Smith 
4949566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
4957199da05SBarry Smith         if (jac->offdiag_use_amat) {
4969566063dSJacob Faibussowitsch           PetscCall(MatFindOffBlockDiagonalEntries(pc->mat, &coupling));
4977199da05SBarry Smith         } else {
4989566063dSJacob Faibussowitsch           PetscCall(MatFindOffBlockDiagonalEntries(pc->pmat, &coupling));
4997199da05SBarry Smith         }
5009566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc->mat), nmax - nmin, nmin, 1, &rest));
5019566063dSJacob Faibussowitsch         PetscCall(ISSetIdentity(rest));
5029566063dSJacob Faibussowitsch         PetscCall(PCFieldSplitSetIS(pc, "0", rest));
5039566063dSJacob Faibussowitsch         PetscCall(PCFieldSplitSetIS(pc, "1", coupling));
5049566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&coupling));
5059566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rest));
5066ce1633cSBarry Smith       } else {
5079566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_default", &fieldsplit_default, NULL));
5087287d2a3SDmitry Karpeev         if (!fieldsplit_default) {
509d32f9abdSBarry Smith           /* Allow user to set fields from command line,  if bs was known at the time of PCSetFromOptions_FieldSplit()
510d32f9abdSBarry Smith            then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
5119566063dSJacob Faibussowitsch           PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc));
5129566063dSJacob Faibussowitsch           if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n"));
513d32f9abdSBarry Smith         }
5146dbb499eSCian Wilson         if ((fieldsplit_default || !jac->splitdefined) && !jac->isrestrict) {
5159f001fe8SStefano Zampini           Mat       M = pc->pmat;
516f3b928b9SStefano Zampini           PetscBool isnest;
51780670ca5SBarry Smith           PetscInt  nf;
518f3b928b9SStefano Zampini 
5199566063dSJacob Faibussowitsch           PetscCall(PetscInfo(pc, "Using default splitting of fields\n"));
5209566063dSJacob Faibussowitsch           PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &isnest));
521f3b928b9SStefano Zampini           if (!isnest) {
5229f001fe8SStefano Zampini             M = pc->mat;
5239566063dSJacob Faibussowitsch             PetscCall(PetscObjectTypeCompare((PetscObject)pc->mat, MATNEST, &isnest));
524f3b928b9SStefano Zampini           }
52580670ca5SBarry Smith           if (!isnest) nf = jac->bs;
52680670ca5SBarry Smith           else PetscCall(MatNestGetSize(M, &nf, NULL));
52780670ca5SBarry Smith           for (i = 0; i < nf; i++) {
5286c924f48SJed Brown             char splitname[8];
52980670ca5SBarry Smith 
53063a3b9bcSJacob Faibussowitsch             PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
5319566063dSJacob Faibussowitsch             PetscCall(PCFieldSplitSetFields(pc, splitname, 1, &i, &i));
53279416396SBarry Smith           }
5335d4c12cdSJungho Lee           jac->defaultsplit = PETSC_TRUE;
534521d7252SBarry Smith         }
53566ffff09SJed Brown       }
5366ce1633cSBarry Smith     }
537edf189efSBarry Smith   } else if (jac->nsplits == 1) {
538edf189efSBarry Smith     IS       is2;
539edf189efSBarry Smith     PetscInt nmin, nmax;
540edf189efSBarry Smith 
5410fdf79fbSJacob Faibussowitsch     PetscCheck(ilink->is, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Must provide at least two sets of fields to PCFieldSplit()");
5429566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
5439566063dSJacob Faibussowitsch     PetscCall(ISComplement(ilink->is, nmin, nmax, &is2));
5449566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetIS(pc, "1", is2));
5459566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is2));
546edf189efSBarry Smith   }
547d0af7cd3SBarry Smith 
54863a3b9bcSJacob Faibussowitsch   PetscCheck(jac->nsplits >= 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unhandled case, must have at least two fields, not %" PetscInt_FMT, jac->nsplits);
5493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55069a612a9SBarry Smith }
55169a612a9SBarry Smith 
MatGolubKahanComputeExplicitOperator(Mat A,Mat B,Mat C,Mat * H,PetscReal gkbnu)552d71ae5a4SJacob Faibussowitsch static PetscErrorCode MatGolubKahanComputeExplicitOperator(Mat A, Mat B, Mat C, Mat *H, PetscReal gkbnu)
553d71ae5a4SJacob Faibussowitsch {
554a51937d4SCarola Kruse   Mat       BT, T;
555de482cd7SCarola Kruse   PetscReal nrmT, nrmB;
556a51937d4SCarola Kruse 
557a51937d4SCarola Kruse   PetscFunctionBegin;
5589566063dSJacob Faibussowitsch   PetscCall(MatHermitianTranspose(C, MAT_INITIAL_MATRIX, &T)); /* Test if augmented matrix is symmetric */
5599566063dSJacob Faibussowitsch   PetscCall(MatAXPY(T, -1.0, B, DIFFERENT_NONZERO_PATTERN));
5609566063dSJacob Faibussowitsch   PetscCall(MatNorm(T, NORM_1, &nrmT));
5619566063dSJacob Faibussowitsch   PetscCall(MatNorm(B, NORM_1, &nrmB));
562b0c98d1dSPierre Jolivet   PetscCheck(nrmB <= 0 || nrmT / nrmB < PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Matrix is not symmetric/Hermitian, GKB is not applicable.");
563049d1499SBarry Smith 
564a51937d4SCarola Kruse   /* Compute augmented Lagrangian matrix H = A00 + nu*A01*A01'. This corresponds to */
565a51937d4SCarola Kruse   /* setting N := 1/nu*I in [Ar13].                                                 */
5669566063dSJacob Faibussowitsch   PetscCall(MatHermitianTranspose(B, MAT_INITIAL_MATRIX, &BT));
567fb842aefSJose E. Roman   PetscCall(MatMatMult(B, BT, MAT_INITIAL_MATRIX, PETSC_CURRENT, H)); /* H = A01*A01'          */
5689566063dSJacob Faibussowitsch   PetscCall(MatAYPX(*H, gkbnu, A, DIFFERENT_NONZERO_PATTERN));        /* H = A00 + nu*A01*A01' */
569a51937d4SCarola Kruse 
5709566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&BT));
5719566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&T));
5723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
573a51937d4SCarola Kruse }
574a51937d4SCarola Kruse 
57554a546c1SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *option[], const char *value[], PetscBool *flg);
576514bf10dSMatthew G Knepley 
PCSetUp_FieldSplit(PC pc)577d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetUp_FieldSplit(PC pc)
578d71ae5a4SJacob Faibussowitsch {
57969a612a9SBarry Smith   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
5805a9f2f41SSatish Balay   PC_FieldSplitLink ilink;
5812c9966d7SBarry Smith   PetscInt          i, nsplit;
5822033cbf1SStefano Zampini   PetscBool         matnest = PETSC_FALSE;
58369a612a9SBarry Smith 
58469a612a9SBarry Smith   PetscFunctionBegin;
5855da88fe4STristan Konolige   pc->failedreason = PC_NOERROR;
5869566063dSJacob Faibussowitsch   PetscCall(PCFieldSplitSetDefaults(pc));
58797bbdb24SBarry Smith   nsplit = jac->nsplits;
5885a9f2f41SSatish Balay   ilink  = jac->head;
58980670ca5SBarry Smith   if (pc->pmat) PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
59097bbdb24SBarry Smith 
59197bbdb24SBarry Smith   /* get the matrices for each split */
592704ba839SBarry Smith   if (!jac->issetup) {
5931b9fc7fcSBarry Smith     PetscInt rstart, rend, nslots, bs;
59497bbdb24SBarry Smith 
595704ba839SBarry Smith     jac->issetup = PETSC_TRUE;
596704ba839SBarry Smith 
5975d4c12cdSJungho Lee     /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
5982c9966d7SBarry Smith     if (jac->defaultsplit || !ilink->is) {
5992c9966d7SBarry Smith       if (jac->bs <= 0) jac->bs = nsplit;
6002c9966d7SBarry Smith     }
6014db63379SBarry Smith 
6024db63379SBarry Smith     /*  MatCreateSubMatrix() for [S]BAIJ matrices can only work if the indices include entire blocks of the matrix */
6034db63379SBarry Smith     PetscCall(MatGetBlockSize(pc->pmat, &bs));
6044db63379SBarry Smith     if (bs > 1 && (jac->bs <= bs || jac->bs % bs)) {
6054db63379SBarry Smith       PetscBool blk;
6064db63379SBarry Smith 
6074db63379SBarry Smith       PetscCall(PetscObjectTypeCompareAny((PetscObject)pc->pmat, &blk, MATBAIJ, MATSBAIJ, MATSEQBAIJ, MATSEQSBAIJ, MATMPIBAIJ, MATMPISBAIJ, NULL));
6084db63379SBarry Smith       PetscCheck(!blk, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "Cannot use MATBAIJ with PCFIELDSPLIT and currently set matrix and PC blocksizes");
6094db63379SBarry Smith     }
6104db63379SBarry Smith 
61180670ca5SBarry Smith     if (!matnest) { /* use the matrix blocksize and stride IS to determine the index sets that define the submatrices */
61251f519a2SBarry Smith       bs = jac->bs;
6139566063dSJacob Faibussowitsch       PetscCall(MatGetOwnershipRange(pc->pmat, &rstart, &rend));
6141b9fc7fcSBarry Smith       nslots = (rend - rstart) / bs;
6151b9fc7fcSBarry Smith       for (i = 0; i < nsplit; i++) {
6161b9fc7fcSBarry Smith         if (jac->defaultsplit) {
6179566063dSJacob Faibussowitsch           PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + i, nsplit, &ilink->is));
6182033cbf1SStefano Zampini           PetscCall(PetscObjectReference((PetscObject)ilink->is));
6192033cbf1SStefano Zampini           ilink->is_col = ilink->is;
620704ba839SBarry Smith         } else if (!ilink->is) {
6212033cbf1SStefano Zampini           PetscBool same_fields = PETSC_TRUE;
6222033cbf1SStefano Zampini 
6232033cbf1SStefano Zampini           for (PetscInt k = 0; k < ilink->nfields; k++) {
6242033cbf1SStefano Zampini             if (ilink->fields[k] != ilink->fields_col[k]) same_fields = PETSC_FALSE;
6252033cbf1SStefano Zampini           }
6262033cbf1SStefano Zampini 
627ccb205f8SBarry Smith           if (ilink->nfields > 1) {
6285f4ab4e1SJungho Lee             PetscInt *ii, *jj, j, k, nfields = ilink->nfields, *fields = ilink->fields, *fields_col = ilink->fields_col;
62980670ca5SBarry Smith 
6309566063dSJacob Faibussowitsch             PetscCall(PetscMalloc1(ilink->nfields * nslots, &ii));
6312033cbf1SStefano Zampini             if (!same_fields) PetscCall(PetscMalloc1(ilink->nfields * nslots, &jj));
6321b9fc7fcSBarry Smith             for (j = 0; j < nslots; j++) {
6331b9fc7fcSBarry Smith               for (k = 0; k < nfields; k++) {
6341b9fc7fcSBarry Smith                 ii[nfields * j + k] = rstart + bs * j + fields[k];
6352033cbf1SStefano Zampini                 if (!same_fields) jj[nfields * j + k] = rstart + bs * j + fields_col[k];
63697bbdb24SBarry Smith               }
63797bbdb24SBarry Smith             }
6389566063dSJacob Faibussowitsch             PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nslots * nfields, ii, PETSC_OWN_POINTER, &ilink->is));
6392033cbf1SStefano Zampini             if (!same_fields) PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nslots * nfields, jj, PETSC_OWN_POINTER, &ilink->is_col));
6402033cbf1SStefano Zampini             else {
6412033cbf1SStefano Zampini               PetscCall(PetscObjectReference((PetscObject)ilink->is));
6422033cbf1SStefano Zampini               ilink->is_col = ilink->is;
6432033cbf1SStefano Zampini             }
6449566063dSJacob Faibussowitsch             PetscCall(ISSetBlockSize(ilink->is, nfields));
6459566063dSJacob Faibussowitsch             PetscCall(ISSetBlockSize(ilink->is_col, nfields));
646ccb205f8SBarry Smith           } else {
6479566063dSJacob Faibussowitsch             PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + ilink->fields[0], bs, &ilink->is));
6482033cbf1SStefano Zampini             if (!same_fields) PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + ilink->fields_col[0], bs, &ilink->is_col));
6492033cbf1SStefano Zampini             else {
6502033cbf1SStefano Zampini               PetscCall(PetscObjectReference((PetscObject)ilink->is));
6512033cbf1SStefano Zampini               ilink->is_col = ilink->is;
652ccb205f8SBarry Smith             }
6533e197d65SBarry Smith           }
6542033cbf1SStefano Zampini         }
655704ba839SBarry Smith         ilink = ilink->next;
6561b9fc7fcSBarry Smith       }
65780670ca5SBarry Smith     } else { /* use the IS that define the MATNEST to determine the index sets that define the submatrices */
65880670ca5SBarry Smith       IS      *rowis, *colis, *ises = NULL;
65980670ca5SBarry Smith       PetscInt mis, nis;
66080670ca5SBarry Smith 
66180670ca5SBarry Smith       PetscCall(MatNestGetSize(pc->pmat, &mis, &nis));
66280670ca5SBarry Smith       PetscCall(PetscMalloc2(mis, &rowis, nis, &colis));
66380670ca5SBarry Smith       PetscCall(MatNestGetISs(pc->pmat, rowis, colis));
66480670ca5SBarry Smith       if (!jac->defaultsplit) PetscCall(PetscMalloc1(mis, &ises));
66580670ca5SBarry Smith 
66680670ca5SBarry Smith       for (i = 0; i < nsplit; i++) {
66780670ca5SBarry Smith         if (jac->defaultsplit) {
66880670ca5SBarry Smith           PetscCall(ISDuplicate(rowis[i], &ilink->is));
6692033cbf1SStefano Zampini           PetscCall(PetscObjectReference((PetscObject)ilink->is));
6702033cbf1SStefano Zampini           ilink->is_col = ilink->is;
67180670ca5SBarry Smith         } else if (!ilink->is) {
67280670ca5SBarry Smith           if (ilink->nfields > 1) {
67380670ca5SBarry Smith             for (PetscInt j = 0; j < ilink->nfields; j++) ises[j] = rowis[ilink->fields[j]];
67480670ca5SBarry Smith             PetscCall(ISConcatenate(PetscObjectComm((PetscObject)pc), ilink->nfields, ises, &ilink->is));
67580670ca5SBarry Smith           } else {
67680670ca5SBarry Smith             PetscCall(ISDuplicate(rowis[ilink->fields[0]], &ilink->is));
67780670ca5SBarry Smith           }
6782033cbf1SStefano Zampini           PetscCall(PetscObjectReference((PetscObject)ilink->is));
6792033cbf1SStefano Zampini           ilink->is_col = ilink->is;
68080670ca5SBarry Smith         }
68180670ca5SBarry Smith         ilink = ilink->next;
68280670ca5SBarry Smith       }
68380670ca5SBarry Smith       PetscCall(PetscFree2(rowis, colis));
68480670ca5SBarry Smith       PetscCall(PetscFree(ises));
68580670ca5SBarry Smith     }
6861b9fc7fcSBarry Smith   }
6871b9fc7fcSBarry Smith 
688704ba839SBarry Smith   ilink = jac->head;
68997bbdb24SBarry Smith   if (!jac->pmat) {
690bdddcaaaSMatthew G Knepley     Vec xtmp;
691bdddcaaaSMatthew G Knepley 
6929566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(pc->pmat, &xtmp, NULL));
6939566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nsplit, &jac->pmat));
6949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nsplit, &jac->x, nsplit, &jac->y));
695cf502942SBarry Smith     for (i = 0; i < nsplit; i++) {
696bdddcaaaSMatthew G Knepley       MatNullSpace sp;
697bdddcaaaSMatthew G Knepley 
6987addb90fSBarry Smith       /* Check for matrix attached to IS */
6999566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)ilink->is, "pmat", (PetscObject *)&jac->pmat[i]));
700a3df900dSMatthew G Knepley       if (jac->pmat[i]) {
7019566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)jac->pmat[i]));
702a3df900dSMatthew G Knepley         if (jac->type == PC_COMPOSITE_SCHUR) {
703a3df900dSMatthew G Knepley           jac->schur_user = jac->pmat[i];
7042fa5cd67SKarl Rupp 
7059566063dSJacob Faibussowitsch           PetscCall(PetscObjectReference((PetscObject)jac->schur_user));
706a3df900dSMatthew G Knepley         }
707a3df900dSMatthew G Knepley       } else {
7083a062f41SBarry Smith         const char *prefix;
7099566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ilink->is_col, MAT_INITIAL_MATRIX, &jac->pmat[i]));
7102f427464SPierre Jolivet         PetscCall(MatGetOptionsPrefix(jac->pmat[i], &prefix));
7112f427464SPierre Jolivet         if (!prefix) {
7129566063dSJacob Faibussowitsch           PetscCall(KSPGetOptionsPrefix(ilink->ksp, &prefix));
7139566063dSJacob Faibussowitsch           PetscCall(MatSetOptionsPrefix(jac->pmat[i], prefix));
7142f427464SPierre Jolivet         }
71545881c45SPierre Jolivet         PetscCall(MatSetFromOptions(jac->pmat[i]));
7169566063dSJacob Faibussowitsch         PetscCall(MatViewFromOptions(jac->pmat[i], NULL, "-mat_view"));
717a3df900dSMatthew G Knepley       }
718bdddcaaaSMatthew G Knepley       /* create work vectors for each split */
7199566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(jac->pmat[i], &jac->x[i], &jac->y[i]));
7209371c9d4SSatish Balay       ilink->x = jac->x[i];
7219371c9d4SSatish Balay       ilink->y = jac->y[i];
7229371c9d4SSatish Balay       ilink->z = NULL;
723bdddcaaaSMatthew G Knepley       /* compute scatter contexts needed by multiplicative versions and non-default splits */
7249566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(xtmp, ilink->is, jac->x[i], NULL, &ilink->sctx));
7259566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)ilink->is, "nearnullspace", (PetscObject *)&sp));
72648a46eb9SPierre Jolivet       if (sp) PetscCall(MatSetNearNullSpace(jac->pmat[i], sp));
727704ba839SBarry Smith       ilink = ilink->next;
728cf502942SBarry Smith     }
7299566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xtmp));
73097bbdb24SBarry Smith   } else {
731ef7efd37SHong Zhang     MatReuse      scall;
7324849c82aSBarry Smith     MatNullSpace *nullsp = NULL;
7334849c82aSBarry Smith 
734ef7efd37SHong Zhang     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
7354849c82aSBarry Smith       PetscCall(MatGetNullSpaces(nsplit, jac->pmat, &nullsp));
73648a46eb9SPierre Jolivet       for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->pmat[i]));
737ef7efd37SHong Zhang       scall = MAT_INITIAL_MATRIX;
738ef7efd37SHong Zhang     } else scall = MAT_REUSE_MATRIX;
739ef7efd37SHong Zhang 
740cf502942SBarry Smith     for (i = 0; i < nsplit; i++) {
741a3df900dSMatthew G Knepley       Mat pmat;
742a3df900dSMatthew G Knepley 
7437addb90fSBarry Smith       /* Check for matrix attached to IS */
7449566063dSJacob Faibussowitsch       PetscCall(PetscObjectQuery((PetscObject)ilink->is, "pmat", (PetscObject *)&pmat));
74548a46eb9SPierre Jolivet       if (!pmat) PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ilink->is_col, scall, &jac->pmat[i]));
746704ba839SBarry Smith       ilink = ilink->next;
747cf502942SBarry Smith     }
7484849c82aSBarry Smith     if (nullsp) PetscCall(MatRestoreNullSpaces(nsplit, jac->pmat, &nullsp));
74997bbdb24SBarry Smith   }
7504e39094bSDmitry Karpeev   if (jac->diag_use_amat) {
751519d70e2SJed Brown     ilink = jac->head;
752519d70e2SJed Brown     if (!jac->mat) {
7539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nsplit, &jac->mat));
754519d70e2SJed Brown       for (i = 0; i < nsplit; i++) {
7559566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ilink->is_col, MAT_INITIAL_MATRIX, &jac->mat[i]));
756519d70e2SJed Brown         ilink = ilink->next;
757519d70e2SJed Brown       }
758519d70e2SJed Brown     } else {
759ef7efd37SHong Zhang       MatReuse      scall;
7604849c82aSBarry Smith       MatNullSpace *nullsp = NULL;
7614849c82aSBarry Smith 
762ef7efd37SHong Zhang       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
7634849c82aSBarry Smith         PetscCall(MatGetNullSpaces(nsplit, jac->mat, &nullsp));
76448a46eb9SPierre Jolivet         for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->mat[i]));
765ef7efd37SHong Zhang         scall = MAT_INITIAL_MATRIX;
766ef7efd37SHong Zhang       } else scall = MAT_REUSE_MATRIX;
767ef7efd37SHong Zhang 
768ef7efd37SHong Zhang       for (i = 0; i < nsplit; i++) {
7699566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ilink->is_col, scall, &jac->mat[i]));
770519d70e2SJed Brown         ilink = ilink->next;
771519d70e2SJed Brown       }
7724849c82aSBarry Smith       if (nullsp) PetscCall(MatRestoreNullSpaces(nsplit, jac->mat, &nullsp));
773519d70e2SJed Brown     }
774519d70e2SJed Brown   } else {
775519d70e2SJed Brown     jac->mat = jac->pmat;
776519d70e2SJed Brown   }
77797bbdb24SBarry Smith 
77853935eafSBarry Smith   /* Check for null space attached to IS */
77953935eafSBarry Smith   ilink = jac->head;
78053935eafSBarry Smith   for (i = 0; i < nsplit; i++) {
78153935eafSBarry Smith     MatNullSpace sp;
78253935eafSBarry Smith 
7839566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)ilink->is, "nullspace", (PetscObject *)&sp));
78448a46eb9SPierre Jolivet     if (sp) PetscCall(MatSetNullSpace(jac->mat[i], sp));
78553935eafSBarry Smith     ilink = ilink->next;
78653935eafSBarry Smith   }
78753935eafSBarry Smith 
788a51937d4SCarola Kruse   if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR && jac->type != PC_COMPOSITE_GKB) {
78968dd23aaSBarry Smith     /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
7904e39094bSDmitry Karpeev     /* FIXME: Can/should we reuse jac->mat whenever (jac->diag_use_amat) is true? */
79168dd23aaSBarry Smith     ilink = jac->head;
792e52d2c62SBarry Smith     if (nsplit == 2 && jac->type == PC_COMPOSITE_MULTIPLICATIVE) {
793e52d2c62SBarry Smith       /* special case need where Afield[0] is not needed and only certain columns of Afield[1] are needed since update is only on those rows of the solution */
794e52d2c62SBarry Smith       if (!jac->Afield) {
7959566063dSJacob Faibussowitsch         PetscCall(PetscCalloc1(nsplit, &jac->Afield));
79680c96bb1SFande Kong         if (jac->offdiag_use_amat) {
7979566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pc->mat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->Afield[1]));
798e52d2c62SBarry Smith         } else {
7999566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pc->pmat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->Afield[1]));
80080c96bb1SFande Kong         }
80180c96bb1SFande Kong       } else {
802ef7efd37SHong Zhang         MatReuse scall;
803e9422dd5SStefano Zampini 
804ef7efd37SHong Zhang         if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
8059566063dSJacob Faibussowitsch           PetscCall(MatDestroy(&jac->Afield[1]));
806ef7efd37SHong Zhang           scall = MAT_INITIAL_MATRIX;
807ef7efd37SHong Zhang         } else scall = MAT_REUSE_MATRIX;
808ef7efd37SHong Zhang 
80980c96bb1SFande Kong         if (jac->offdiag_use_amat) {
8109566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pc->mat, ilink->next->is, ilink->is, scall, &jac->Afield[1]));
81180c96bb1SFande Kong         } else {
8129566063dSJacob Faibussowitsch           PetscCall(MatCreateSubMatrix(pc->pmat, ilink->next->is, ilink->is, scall, &jac->Afield[1]));
81380c96bb1SFande Kong         }
814e52d2c62SBarry Smith       }
815e52d2c62SBarry Smith     } else {
81668dd23aaSBarry Smith       if (!jac->Afield) {
8179566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(nsplit, &jac->Afield));
81868dd23aaSBarry Smith         for (i = 0; i < nsplit; i++) {
81980c96bb1SFande Kong           if (jac->offdiag_use_amat) {
8209566063dSJacob Faibussowitsch             PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, NULL, MAT_INITIAL_MATRIX, &jac->Afield[i]));
82180c96bb1SFande Kong           } else {
8229566063dSJacob Faibussowitsch             PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, NULL, MAT_INITIAL_MATRIX, &jac->Afield[i]));
82380c96bb1SFande Kong           }
82468dd23aaSBarry Smith           ilink = ilink->next;
82568dd23aaSBarry Smith         }
82668dd23aaSBarry Smith       } else {
827ef7efd37SHong Zhang         MatReuse scall;
828ef7efd37SHong Zhang         if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
82948a46eb9SPierre Jolivet           for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->Afield[i]));
830ef7efd37SHong Zhang           scall = MAT_INITIAL_MATRIX;
831ef7efd37SHong Zhang         } else scall = MAT_REUSE_MATRIX;
832ef7efd37SHong Zhang 
83368dd23aaSBarry Smith         for (i = 0; i < nsplit; i++) {
83480c96bb1SFande Kong           if (jac->offdiag_use_amat) {
8359566063dSJacob Faibussowitsch             PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, NULL, scall, &jac->Afield[i]));
83680c96bb1SFande Kong           } else {
8379566063dSJacob Faibussowitsch             PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, NULL, scall, &jac->Afield[i]));
83880c96bb1SFande Kong           }
83968dd23aaSBarry Smith           ilink = ilink->next;
84068dd23aaSBarry Smith         }
84168dd23aaSBarry Smith       }
84268dd23aaSBarry Smith     }
843e52d2c62SBarry Smith   }
84468dd23aaSBarry Smith 
8453b224e63SBarry Smith   if (jac->type == PC_COMPOSITE_SCHUR) {
84618f54938SStefano Zampini     PetscBool   isset, isspd = PETSC_FALSE, issym = PETSC_FALSE, flg;
847093c86ffSJed Brown     char        lscname[256];
848093c86ffSJed Brown     PetscObject LSC_L;
849ce94432eSBarry Smith 
85008401ef6SPierre Jolivet     PetscCheck(nsplit == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "To use Schur complement preconditioner you must have exactly 2 fields");
85168dd23aaSBarry Smith 
852c096484dSStefano Zampini     /* If pc->mat is SPD, don't scale by -1 the Schur complement */
853b94d7dedSBarry Smith     PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
85418f54938SStefano Zampini     if (jac->schurscale == (PetscScalar)-1.0) jac->schurscale = (isset && isspd) ? 1.0 : -1.0;
85518f54938SStefano Zampini     PetscCall(MatIsSymmetricKnown(pc->pmat, &isset, &issym));
856c096484dSStefano Zampini 
857558f3fe8SPierre Jolivet     PetscCall(PetscObjectTypeCompareAny(jac->offdiag_use_amat ? (PetscObject)pc->mat : (PetscObject)pc->pmat, &flg, MATSEQSBAIJ, MATMPISBAIJ, ""));
858e6cab6aaSJed Brown 
8593b224e63SBarry Smith     if (jac->schur) {
8600298fd71SBarry Smith       KSP      kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper;
861e9422dd5SStefano Zampini       MatReuse scall;
862e9422dd5SStefano Zampini 
863e9422dd5SStefano Zampini       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
864e9422dd5SStefano Zampini         scall = MAT_INITIAL_MATRIX;
8659566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&jac->B));
8669566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&jac->C));
867e9422dd5SStefano Zampini       } else scall = MAT_REUSE_MATRIX;
868443836d0SMatthew G Knepley 
8699566063dSJacob Faibussowitsch       PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
8703b224e63SBarry Smith       ilink = jac->head;
871ad881d7cSPierre Jolivet       PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->is, ilink->next->is, scall, &jac->B));
872ad881d7cSPierre Jolivet       if (!flg) PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->next->is, ilink->is, scall, &jac->C));
873ad881d7cSPierre Jolivet       else {
87418f54938SStefano Zampini         PetscCall(MatIsHermitianKnown(jac->offdiag_use_amat ? pc->mat : pc->pmat, &isset, &flg));
87518f54938SStefano Zampini         if (isset && flg) PetscCall(MatCreateHermitianTranspose(jac->B, &jac->C));
876558f3fe8SPierre Jolivet         else PetscCall(MatCreateTranspose(jac->B, &jac->C));
877558f3fe8SPierre Jolivet       }
878ad881d7cSPierre Jolivet       ilink = ilink->next;
8799566063dSJacob Faibussowitsch       PetscCall(MatSchurComplementUpdateSubMatrices(jac->schur, jac->mat[0], jac->pmat[0], jac->B, jac->C, jac->mat[1]));
880a7476a74SDmitry Karpeev       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) {
8819566063dSJacob Faibussowitsch         PetscCall(MatDestroy(&jac->schurp));
8829566063dSJacob Faibussowitsch         PetscCall(MatSchurComplementGetPmat(jac->schur, MAT_INITIAL_MATRIX, &jac->schurp));
8835becce15SPierre Jolivet       } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL && jac->kspupper != jac->head->ksp) {
884d9eadc85SPierre Jolivet         PetscCall(MatDestroy(&jac->schur_user));
885d9eadc85SPierre Jolivet         PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
886a7476a74SDmitry Karpeev       }
88748a46eb9SPierre Jolivet       if (kspA != kspInner) PetscCall(KSPSetOperators(kspA, jac->mat[0], jac->pmat[0]));
88848a46eb9SPierre Jolivet       if (kspUpper != kspA) PetscCall(KSPSetOperators(kspUpper, jac->mat[0], jac->pmat[0]));
8899566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->kspschur, jac->schur, FieldSplitSchurPre(jac)));
8903b224e63SBarry Smith     } else {
891bafc1b83SMatthew G Knepley       const char  *Dprefix;
892470b340bSDmitry Karpeev       char         schurprefix[256], schurmatprefix[256];
893514bf10dSMatthew G Knepley       char         schurtestoption[256];
894bdddcaaaSMatthew G Knepley       MatNullSpace sp;
895686bed4dSStefano Zampini       KSP          kspt;
8963b224e63SBarry Smith 
897a04f6461SBarry Smith       /* extract the A01 and A10 matrices */
8983b224e63SBarry Smith       ilink = jac->head;
899ad881d7cSPierre Jolivet       PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->is, ilink->next->is, MAT_INITIAL_MATRIX, &jac->B));
900ad881d7cSPierre Jolivet       if (!flg) PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->C));
901ad881d7cSPierre Jolivet       else {
90218f54938SStefano Zampini         PetscCall(MatIsHermitianKnown(jac->offdiag_use_amat ? pc->mat : pc->pmat, &isset, &flg));
90318f54938SStefano Zampini         if (isset && flg) PetscCall(MatCreateHermitianTranspose(jac->B, &jac->C));
904558f3fe8SPierre Jolivet         else PetscCall(MatCreateTranspose(jac->B, &jac->C));
905558f3fe8SPierre Jolivet       }
906ad881d7cSPierre Jolivet       ilink = ilink->next;
907f5236f50SJed Brown       /* Use mat[0] (diagonal block of Amat) preconditioned by pmat[0] to define Schur complement */
9089566063dSJacob Faibussowitsch       PetscCall(MatCreate(((PetscObject)jac->mat[0])->comm, &jac->schur));
9099566063dSJacob Faibussowitsch       PetscCall(MatSetType(jac->schur, MATSCHURCOMPLEMENT));
9109566063dSJacob Faibussowitsch       PetscCall(MatSchurComplementSetSubMatrices(jac->schur, jac->mat[0], jac->pmat[0], jac->B, jac->C, jac->mat[1]));
9119566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(schurmatprefix, sizeof(schurmatprefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
9129566063dSJacob Faibussowitsch       PetscCall(MatSetOptionsPrefix(jac->schur, schurmatprefix));
9139566063dSJacob Faibussowitsch       PetscCall(MatSchurComplementGetKSP(jac->schur, &kspt));
9149566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(kspt, schurmatprefix));
915686bed4dSStefano Zampini 
916686bed4dSStefano Zampini       /* Note: this is not true in general */
9179566063dSJacob Faibussowitsch       PetscCall(MatGetNullSpace(jac->mat[1], &sp));
9181baa6e33SBarry Smith       if (sp) PetscCall(MatSetNullSpace(jac->schur, sp));
91920252d06SBarry Smith 
9209566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname));
92154a546c1SMatthew G. Knepley       PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, schurtestoption, NULL, NULL, &flg));
922514bf10dSMatthew G Knepley       if (flg) {
923514bf10dSMatthew G Knepley         DM  dmInner;
92421635b76SJed Brown         KSP kspInner;
925686bed4dSStefano Zampini         PC  pcInner;
92621635b76SJed Brown 
9279566063dSJacob Faibussowitsch         PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
9289566063dSJacob Faibussowitsch         PetscCall(KSPReset(kspInner));
9299566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(kspInner, jac->mat[0], jac->pmat[0]));
9309566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
93121635b76SJed Brown         /* Indent this deeper to emphasize the "inner" nature of this solver. */
9329566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspInner, (PetscObject)pc, 2));
9339566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspInner->pc, (PetscObject)pc, 2));
9349566063dSJacob Faibussowitsch         PetscCall(KSPSetOptionsPrefix(kspInner, schurprefix));
935514bf10dSMatthew G Knepley 
936514bf10dSMatthew G Knepley         /* Set DM for new solver */
9379566063dSJacob Faibussowitsch         PetscCall(KSPGetDM(jac->head->ksp, &dmInner));
9389566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(kspInner, dmInner));
939*bf0c7fc2SBarry Smith         PetscCall(KSPSetDMActive(kspInner, KSP_DMACTIVE_ALL, PETSC_FALSE));
940686bed4dSStefano Zampini 
941686bed4dSStefano Zampini         /* Defaults to PCKSP as preconditioner */
9429566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(kspInner, &pcInner));
9439566063dSJacob Faibussowitsch         PetscCall(PCSetType(pcInner, PCKSP));
9449566063dSJacob Faibussowitsch         PetscCall(PCKSPSetKSP(pcInner, jac->head->ksp));
945514bf10dSMatthew G Knepley       } else {
94621635b76SJed Brown         /* Use the outer solver for the inner solve, but revert the KSPPREONLY from PCFieldSplitSetFields_FieldSplit or
94721635b76SJed Brown           * PCFieldSplitSetIS_FieldSplit. We don't want KSPPREONLY because it makes the Schur complement inexact,
94821635b76SJed Brown           * preventing Schur complement reduction to be an accurate solve. Usually when an iterative solver is used for
94921635b76SJed Brown           * S = D - C A_inner^{-1} B, we expect S to be defined using an accurate definition of A_inner^{-1}, so we make
95021635b76SJed Brown           * GMRES the default. Note that it is also common to use PREONLY for S, in which case S may not be used
95121635b76SJed Brown           * directly, and the user is responsible for setting an inexact method for fieldsplit's A^{-1}. */
9529566063dSJacob Faibussowitsch         PetscCall(KSPSetType(jac->head->ksp, KSPGMRES));
9539566063dSJacob Faibussowitsch         PetscCall(MatSchurComplementSetKSP(jac->schur, jac->head->ksp));
954bafc1b83SMatthew G Knepley       }
9559566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->head->ksp, jac->mat[0], jac->pmat[0]));
9569566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(jac->head->ksp));
9579566063dSJacob Faibussowitsch       PetscCall(MatSetFromOptions(jac->schur));
9583b224e63SBarry Smith 
9599566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)jac->schur, MATSCHURCOMPLEMENT, &flg));
960686bed4dSStefano Zampini       if (flg) { /* Need to do this otherwise PCSetUp_KSP will overwrite the amat of jac->head->ksp */
961686bed4dSStefano Zampini         KSP kspInner;
962686bed4dSStefano Zampini         PC  pcInner;
963686bed4dSStefano Zampini 
9649566063dSJacob Faibussowitsch         PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
9659566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(kspInner, &pcInner));
9669566063dSJacob Faibussowitsch         PetscCall(PetscObjectTypeCompare((PetscObject)pcInner, PCKSP, &flg));
967686bed4dSStefano Zampini         if (flg) {
968686bed4dSStefano Zampini           KSP ksp;
969686bed4dSStefano Zampini 
9709566063dSJacob Faibussowitsch           PetscCall(PCKSPGetKSP(pcInner, &ksp));
97148a46eb9SPierre Jolivet           if (ksp == jac->head->ksp) PetscCall(PCSetUseAmat(pcInner, PETSC_TRUE));
972686bed4dSStefano Zampini         }
973686bed4dSStefano Zampini       }
9749566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname));
97554a546c1SMatthew G. Knepley       PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, schurtestoption, NULL, NULL, &flg));
976443836d0SMatthew G Knepley       if (flg) {
977443836d0SMatthew G Knepley         DM dmInner;
978443836d0SMatthew G Knepley 
9799566063dSJacob Faibussowitsch         PetscCall(PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
9809566063dSJacob Faibussowitsch         PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspupper));
9813821be0aSBarry Smith         PetscCall(KSPSetNestLevel(jac->kspupper, pc->kspnestlevel));
9829566063dSJacob Faibussowitsch         PetscCall(KSPSetErrorIfNotConverged(jac->kspupper, pc->erroriffailure));
9839566063dSJacob Faibussowitsch         PetscCall(KSPSetOptionsPrefix(jac->kspupper, schurprefix));
9849566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspupper, (PetscObject)pc, 1));
9859566063dSJacob Faibussowitsch         PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspupper->pc, (PetscObject)pc, 1));
9869566063dSJacob Faibussowitsch         PetscCall(KSPGetDM(jac->head->ksp, &dmInner));
9879566063dSJacob Faibussowitsch         PetscCall(KSPSetDM(jac->kspupper, dmInner));
988*bf0c7fc2SBarry Smith         PetscCall(KSPSetDMActive(jac->kspupper, KSP_DMACTIVE_ALL, PETSC_FALSE));
9899566063dSJacob Faibussowitsch         PetscCall(KSPSetFromOptions(jac->kspupper));
9909566063dSJacob Faibussowitsch         PetscCall(KSPSetOperators(jac->kspupper, jac->mat[0], jac->pmat[0]));
9919566063dSJacob Faibussowitsch         PetscCall(VecDuplicate(jac->head->x, &jac->head->z));
992443836d0SMatthew G Knepley       } else {
993443836d0SMatthew G Knepley         jac->kspupper = jac->head->ksp;
9949566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)jac->head->ksp));
995443836d0SMatthew G Knepley       }
996443836d0SMatthew G Knepley 
99748a46eb9SPierre Jolivet       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) PetscCall(MatSchurComplementGetPmat(jac->schur, MAT_INITIAL_MATRIX, &jac->schurp));
9989566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspschur));
9993821be0aSBarry Smith       PetscCall(KSPSetNestLevel(jac->kspschur, pc->kspnestlevel));
10009566063dSJacob Faibussowitsch       PetscCall(KSPSetErrorIfNotConverged(jac->kspschur, pc->erroriffailure));
10019566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspschur, (PetscObject)pc, 1));
1002084e4875SJed Brown       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
10037233a360SDmitry Karpeev         PC pcschur;
10049566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(jac->kspschur, &pcschur));
10059566063dSJacob Faibussowitsch         PetscCall(PCSetType(pcschur, PCNONE));
1006084e4875SJed Brown         /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
1007e74569cdSMatthew G. Knepley       } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL) {
10085becce15SPierre Jolivet         if (jac->schurfactorization != PC_FIELDSPLIT_SCHUR_FACT_FULL || jac->kspupper != jac->head->ksp) PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
1009e69d4d44SBarry Smith       }
10109566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->kspschur, jac->schur, FieldSplitSchurPre(jac)));
10119566063dSJacob Faibussowitsch       PetscCall(KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix));
10129566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(jac->kspschur, Dprefix));
1013c096484dSStefano Zampini       /* propagate DM */
1014b20b4189SMatthew G. Knepley       {
1015b20b4189SMatthew G. Knepley         DM sdm;
10169566063dSJacob Faibussowitsch         PetscCall(KSPGetDM(jac->head->next->ksp, &sdm));
1017b20b4189SMatthew G. Knepley         if (sdm) {
10189566063dSJacob Faibussowitsch           PetscCall(KSPSetDM(jac->kspschur, sdm));
1019*bf0c7fc2SBarry Smith           PetscCall(KSPSetDMActive(jac->kspschur, KSP_DMACTIVE_ALL, PETSC_FALSE));
1020b20b4189SMatthew G. Knepley         }
1021b20b4189SMatthew G. Knepley       }
10223b224e63SBarry Smith       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
102320b26d62SBarry Smith       /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */
10249566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(jac->kspschur));
10253b224e63SBarry Smith     }
10269566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(jac->schur, MAT_FINAL_ASSEMBLY));
10279566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(jac->schur, MAT_FINAL_ASSEMBLY));
102818f54938SStefano Zampini     if (issym) PetscCall(MatSetOption(jac->schur, MAT_SYMMETRIC, PETSC_TRUE));
102918f54938SStefano Zampini     if (isspd) PetscCall(MatSetOption(jac->schur, MAT_SPD, PETSC_TRUE));
1030093c86ffSJed Brown 
1031093c86ffSJed Brown     /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */
10329566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(lscname, sizeof(lscname), "%s_LSC_L", ilink->splitname));
1033835f2295SStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)pc->mat, lscname, &LSC_L));
1034835f2295SStefano Zampini     if (!LSC_L) PetscCall(PetscObjectQuery((PetscObject)pc->pmat, lscname, &LSC_L));
1035835f2295SStefano Zampini     if (LSC_L) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "LSC_L", LSC_L));
10369566063dSJacob Faibussowitsch     PetscCall(PetscSNPrintf(lscname, sizeof(lscname), "%s_LSC_Lp", ilink->splitname));
1037835f2295SStefano Zampini     PetscCall(PetscObjectQuery((PetscObject)pc->pmat, lscname, &LSC_L));
1038835f2295SStefano Zampini     if (!LSC_L) PetscCall(PetscObjectQuery((PetscObject)pc->mat, lscname, &LSC_L));
1039835f2295SStefano Zampini     if (LSC_L) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "LSC_Lp", LSC_L));
1040a51937d4SCarola Kruse   } else if (jac->type == PC_COMPOSITE_GKB) {
104108401ef6SPierre Jolivet     PetscCheck(nsplit == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "To use GKB preconditioner you must have exactly 2 fields");
1042a51937d4SCarola Kruse     ilink = jac->head;
1043ad881d7cSPierre Jolivet     PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->is, ilink->next->is, MAT_INITIAL_MATRIX, &jac->B));
1044e071a0a4SCarola Kruse     /* Create work vectors for GKB algorithm */
10459566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ilink->x, &jac->u));
10469566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ilink->x, &jac->Hu));
10479566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ilink->x, &jac->w2));
1048ad881d7cSPierre Jolivet     PetscCall(MatCreateSubMatrix(jac->offdiag_use_amat ? pc->mat : pc->pmat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->C));
1049a51937d4SCarola Kruse     ilink = ilink->next;
1050e071a0a4SCarola Kruse     /* Create work vectors for GKB algorithm */
10519566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ilink->x, &jac->v));
10529566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ilink->x, &jac->d));
10539566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(ilink->x, &jac->w1));
10549566063dSJacob Faibussowitsch     PetscCall(MatGolubKahanComputeExplicitOperator(jac->mat[0], jac->B, jac->C, &jac->H, jac->gkbnu));
10559566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(jac->gkbdelay, &jac->vecz));
1056e071a0a4SCarola Kruse 
1057a51937d4SCarola Kruse     ilink = jac->head;
10589566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(ilink->ksp, jac->H, jac->H));
10599566063dSJacob Faibussowitsch     if (!jac->suboptionsset) PetscCall(KSPSetFromOptions(ilink->ksp));
1060e071a0a4SCarola Kruse     /* Create gkb_monitor context */
1061de482cd7SCarola Kruse     if (jac->gkbmonitor) {
1062de482cd7SCarola Kruse       PetscInt tablevel;
10639566063dSJacob Faibussowitsch       PetscCall(PetscViewerCreate(PETSC_COMM_WORLD, &jac->gkbviewer));
10649566063dSJacob Faibussowitsch       PetscCall(PetscViewerSetType(jac->gkbviewer, PETSCVIEWERASCII));
10659566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetTabLevel((PetscObject)ilink->ksp, &tablevel));
10669566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIISetTab(jac->gkbviewer, tablevel));
10679566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)ilink->ksp, 1));
1068de482cd7SCarola Kruse     }
10693b224e63SBarry Smith   } else {
107068bd789dSDmitry Karpeev     /* set up the individual splits' PCs */
107197bbdb24SBarry Smith     i     = 0;
10725a9f2f41SSatish Balay     ilink = jac->head;
10735a9f2f41SSatish Balay     while (ilink) {
10749566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(ilink->ksp, jac->mat[i], jac->pmat[i]));
10753b224e63SBarry Smith       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
10769566063dSJacob Faibussowitsch       if (!jac->suboptionsset) PetscCall(KSPSetFromOptions(ilink->ksp));
107797bbdb24SBarry Smith       i++;
10785a9f2f41SSatish Balay       ilink = ilink->next;
10790971522cSBarry Smith     }
10803b224e63SBarry Smith   }
10813b224e63SBarry Smith 
10825ddf11f8SNicolas Barnafi   /* Set coordinates to the sub PC objects whenever these are set */
10835ddf11f8SNicolas Barnafi   if (jac->coordinates_set) {
10845ddf11f8SNicolas Barnafi     PC pc_coords;
10855ddf11f8SNicolas Barnafi     if (jac->type == PC_COMPOSITE_SCHUR) {
10865ddf11f8SNicolas Barnafi       // Head is first block.
10879566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(jac->head->ksp, &pc_coords));
10889566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_coords, jac->head->dim, jac->head->ndofs, jac->head->coords));
10895ddf11f8SNicolas Barnafi       // Second one is Schur block, but its KSP object is in kspschur.
10909566063dSJacob Faibussowitsch       PetscCall(KSPGetPC(jac->kspschur, &pc_coords));
10919566063dSJacob Faibussowitsch       PetscCall(PCSetCoordinates(pc_coords, jac->head->next->dim, jac->head->next->ndofs, jac->head->next->coords));
10925ddf11f8SNicolas Barnafi     } else if (jac->type == PC_COMPOSITE_GKB) {
10939d3446b2SPierre Jolivet       PetscCall(PetscInfo(pc, "Warning: Setting coordinates does nothing for the GKB Fieldpslit preconditioner\n"));
10945ddf11f8SNicolas Barnafi     } else {
10955ddf11f8SNicolas Barnafi       ilink = jac->head;
10965ddf11f8SNicolas Barnafi       while (ilink) {
10979566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(ilink->ksp, &pc_coords));
10989566063dSJacob Faibussowitsch         PetscCall(PCSetCoordinates(pc_coords, ilink->dim, ilink->ndofs, ilink->coords));
10995ddf11f8SNicolas Barnafi         ilink = ilink->next;
11005ddf11f8SNicolas Barnafi       }
11015ddf11f8SNicolas Barnafi     }
11025ddf11f8SNicolas Barnafi   }
11035ddf11f8SNicolas Barnafi 
1104c1570756SJed Brown   jac->suboptionsset = PETSC_TRUE;
11053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11060971522cSBarry Smith }
11070971522cSBarry Smith 
PCSetUpOnBlocks_FieldSplit_Schur(PC pc)110873716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit_Schur(PC pc)
110973716367SStefano Zampini {
111073716367SStefano Zampini   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
111173716367SStefano Zampini   PC_FieldSplitLink ilinkA = jac->head;
111273716367SStefano Zampini   KSP               kspA = ilinkA->ksp, kspUpper = jac->kspupper;
111373716367SStefano Zampini 
111473716367SStefano Zampini   PetscFunctionBegin;
111573716367SStefano Zampini   if (jac->schurfactorization == PC_FIELDSPLIT_SCHUR_FACT_FULL && kspUpper != kspA) {
111673716367SStefano Zampini     PetscCall(KSPSetUp(kspUpper));
111773716367SStefano Zampini     PetscCall(KSPSetUpOnBlocks(kspUpper));
111873716367SStefano Zampini   }
111973716367SStefano Zampini   PetscCall(KSPSetUp(kspA));
112073716367SStefano Zampini   PetscCall(KSPSetUpOnBlocks(kspA));
112173716367SStefano Zampini   if (jac->schurpre != PC_FIELDSPLIT_SCHUR_PRE_FULL) {
112273716367SStefano Zampini     PetscCall(KSPSetUp(jac->kspschur));
112373716367SStefano Zampini     PetscCall(KSPSetUpOnBlocks(jac->kspschur));
1124c9d0a0b7SPierre Jolivet   } else if (kspUpper == kspA && jac->schurfactorization == PC_FIELDSPLIT_SCHUR_FACT_FULL) {
11255becce15SPierre Jolivet     Mat          A;
1126ab1f0642SPierre Jolivet     PetscInt     m, M, N;
1127ab1f0642SPierre Jolivet     VecType      vtype;
1128ab1f0642SPierre Jolivet     PetscMemType mtype;
1129ab1f0642SPierre Jolivet     PetscScalar *array;
1130ab1f0642SPierre Jolivet 
1131ab1f0642SPierre Jolivet     PetscCall(MatGetSize(jac->B, &M, &N));
1132ab1f0642SPierre Jolivet     PetscCall(MatGetLocalSize(jac->B, &m, NULL));
1133ab1f0642SPierre Jolivet     PetscCall(MatGetVecType(jac->B, &vtype));
1134ab1f0642SPierre Jolivet     PetscCall(VecGetArrayAndMemType(ilinkA->x, &array, &mtype));
1135ab1f0642SPierre Jolivet     PetscCall(VecRestoreArrayAndMemType(ilinkA->x, &array));
1136c9d0a0b7SPierre Jolivet     PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&A));
1137cb03e585SPierre Jolivet     if (A) {
1138cb03e585SPierre Jolivet       PetscInt P;
1139cb03e585SPierre Jolivet 
1140cb03e585SPierre Jolivet       PetscCall(MatGetSize(A, NULL, &P));
1141cb03e585SPierre Jolivet       if (P < N + 1) { // need to recreate AinvB, otherwise, the Schur complement won't be updated
1142cb03e585SPierre Jolivet         PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", NULL));
1143cb03e585SPierre Jolivet         A = NULL;
1144cb03e585SPierre Jolivet       }
1145cb03e585SPierre Jolivet     }
1146c9d0a0b7SPierre Jolivet     if (!A) {
1147ab1f0642SPierre Jolivet       if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(PetscMalloc1(m * (N + 1), &array));
1148ab1f0642SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1149ab1f0642SPierre Jolivet       else if (PetscMemTypeCUDA(mtype)) PetscCallCUDA(cudaMalloc((void **)&array, sizeof(PetscScalar) * m * (N + 1)));
1150ab1f0642SPierre Jolivet #endif
1151ab1f0642SPierre Jolivet #if PetscDefined(HAVE_HIP)
1152ab1f0642SPierre Jolivet       else if (PetscMemTypeHIP(mtype)) PetscCallHIP(hipMalloc((void **)&array, sizeof(PetscScalar) * m * (N + 1)));
1153ab1f0642SPierre Jolivet #endif
1154ab1f0642SPierre Jolivet       PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)jac->schur), vtype, m, PETSC_DECIDE, M, N + 1, -1, array, &A)); // number of columns of the Schur complement plus one
11555becce15SPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", (PetscObject)A));
11565becce15SPierre Jolivet       PetscCall(MatDestroy(&A));
115773716367SStefano Zampini     }
1158c9d0a0b7SPierre Jolivet   }
115973716367SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
116073716367SStefano Zampini }
116173716367SStefano Zampini 
PCSetUpOnBlocks_FieldSplit(PC pc)116273716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit(PC pc)
116373716367SStefano Zampini {
116473716367SStefano Zampini   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
116573716367SStefano Zampini   PC_FieldSplitLink ilink = jac->head;
116673716367SStefano Zampini 
116773716367SStefano Zampini   PetscFunctionBegin;
116873716367SStefano Zampini   while (ilink) {
116973716367SStefano Zampini     PetscCall(KSPSetUp(ilink->ksp));
117073716367SStefano Zampini     PetscCall(KSPSetUpOnBlocks(ilink->ksp));
117173716367SStefano Zampini     ilink = ilink->next;
117273716367SStefano Zampini   }
117373716367SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
117473716367SStefano Zampini }
117573716367SStefano Zampini 
PCSetUpOnBlocks_FieldSplit_GKB(PC pc)117673716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit_GKB(PC pc)
117773716367SStefano Zampini {
117873716367SStefano Zampini   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
117973716367SStefano Zampini   PC_FieldSplitLink ilinkA = jac->head;
118073716367SStefano Zampini   KSP               ksp    = ilinkA->ksp;
118173716367SStefano Zampini 
118273716367SStefano Zampini   PetscFunctionBegin;
118373716367SStefano Zampini   PetscCall(KSPSetUp(ksp));
118473716367SStefano Zampini   PetscCall(KSPSetUpOnBlocks(ksp));
118573716367SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
118673716367SStefano Zampini }
118773716367SStefano Zampini 
PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)1188d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_Schur(PC pc, Vec x, Vec y)
1189d71ae5a4SJacob Faibussowitsch {
11903b224e63SBarry Smith   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
11913b224e63SBarry Smith   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1192443836d0SMatthew G Knepley   KSP               kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
1193d9eadc85SPierre Jolivet   Mat               AinvB = NULL;
1194ab1f0642SPierre Jolivet   PetscInt          N, P;
11953b224e63SBarry Smith 
11963b224e63SBarry Smith   PetscFunctionBegin;
1197c5d2311dSJed Brown   switch (jac->schurfactorization) {
1198c9c6ffaaSJed Brown   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
1199a04f6461SBarry Smith     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
12009566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12019566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12029566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12039566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12049566063dSJacob Faibussowitsch     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
12059566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
12069566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12079566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12089566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12099566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1210e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12119566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
12129566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
1213e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12149566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12159566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->y, jac->schurscale));
12169566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12179566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12189566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1219c5d2311dSJed Brown     break;
1220c9c6ffaaSJed Brown   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
1221a04f6461SBarry Smith     /* [A00 0; A10 S], suitable for left preconditioning */
12229566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12239566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12249566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12259566063dSJacob Faibussowitsch     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
12269566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
12279566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12289566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x));
12299566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->x, -1.));
12309566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
12319566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12329566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
12339566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1234e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12359566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1236e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12379566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
12389566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12399566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12409566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12419566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1242c5d2311dSJed Brown     break;
1243c9c6ffaaSJed Brown   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
1244a04f6461SBarry Smith     /* [A00 A01; 0 S], suitable for right preconditioning */
12459566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12469566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12479566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1248e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12499566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1250e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12519566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
12529371c9d4SSatish Balay     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12539371c9d4SSatish Balay     PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x));
12549566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkA->x, -1.));
12559566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
12569566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12579566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
12589566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12599566063dSJacob Faibussowitsch     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
12609566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
12619566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12629566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12639566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12649566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1265c5d2311dSJed Brown     break;
1266c9c6ffaaSJed Brown   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
1267c238f8cdSStefano Zampini     /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */
1268ab1f0642SPierre Jolivet     PetscCall(MatGetSize(jac->B, NULL, &P));
1269ab1f0642SPierre Jolivet     N = P;
12709566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12719566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12729566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL));
1273d9eadc85SPierre Jolivet     if (kspUpper == kspA) {
1274d9eadc85SPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&AinvB));
1275d9eadc85SPierre Jolivet       if (AinvB) {
1276d9eadc85SPierre Jolivet         PetscCall(MatGetSize(AinvB, NULL, &N));
1277ab1f0642SPierre Jolivet         if (N > P) { // first time PCApply_FieldSplit_Schur() is called
1278f7cbcdf3SPierre Jolivet           PetscMemType mtype;
1279ab1f0642SPierre Jolivet           Vec          c = NULL;
1280f7cbcdf3SPierre Jolivet           PetscScalar *array;
1281ab1f0642SPierre Jolivet           PetscInt     m, M;
1282d9eadc85SPierre Jolivet 
1283ab1f0642SPierre Jolivet           PetscCall(MatGetSize(jac->B, &M, NULL));
1284d9eadc85SPierre Jolivet           PetscCall(MatGetLocalSize(jac->B, &m, NULL));
1285ab1f0642SPierre Jolivet           PetscCall(MatDenseGetArrayAndMemType(AinvB, &array, &mtype));
1286ab1f0642SPierre Jolivet           if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1287f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1288ab1f0642SPierre Jolivet           else if (PetscMemTypeCUDA(mtype)) PetscCall(VecCreateMPICUDAWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1289f7cbcdf3SPierre Jolivet #endif
1290f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_HIP)
1291ab1f0642SPierre Jolivet           else if (PetscMemTypeHIP(mtype)) PetscCall(VecCreateMPIHIPWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1292f7cbcdf3SPierre Jolivet #endif
1293ab1f0642SPierre Jolivet           PetscCall(MatDenseRestoreArrayAndMemType(AinvB, &array));
1294ab1f0642SPierre Jolivet           PetscCall(VecCopy(ilinkA->x, c));
1295d9eadc85SPierre Jolivet           PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
1296d9eadc85SPierre Jolivet           PetscCall(KSPSetOperators(jac->kspschur, jac->schur, jac->schur_user));
1297f7cbcdf3SPierre Jolivet           PetscCall(VecCopy(c, ilinkA->y)); // retrieve the solution as the last column of the composed Mat
1298f7cbcdf3SPierre Jolivet           PetscCall(VecDestroy(&c));
1299d9eadc85SPierre Jolivet         }
1300d9eadc85SPierre Jolivet       }
1301d9eadc85SPierre Jolivet     }
1302ab1f0642SPierre Jolivet     if (N == P) PetscCall(KSPSolve(kspLower, ilinkA->x, ilinkA->y));
13039566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->y));
13049566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL));
13059566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x));
13069566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->x, -1.0));
13079566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
13089566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
13093b224e63SBarry Smith 
13109566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1311e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
13129566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1313e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
13149566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
13159566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
13169566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
13173b224e63SBarry Smith 
1318443836d0SMatthew G Knepley     if (kspUpper == kspA) {
1319d9eadc85SPierre Jolivet       if (!AinvB) {
13209566063dSJacob Faibussowitsch         PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->y));
13219566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y));
13229566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
13239566063dSJacob Faibussowitsch         PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
13249566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
13259566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1326d9eadc85SPierre Jolivet       } else PetscCall(MatMultAdd(AinvB, ilinkD->y, ilinkA->y, ilinkA->y));
1327443836d0SMatthew G Knepley     } else {
13289566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
13299566063dSJacob Faibussowitsch       PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
13309566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
13319566063dSJacob Faibussowitsch       PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x));
13329566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL));
13339566063dSJacob Faibussowitsch       PetscCall(KSPSolve(kspUpper, ilinkA->x, ilinkA->z));
13349566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->z));
13359566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL));
13369566063dSJacob Faibussowitsch       PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z));
1337443836d0SMatthew G Knepley     }
13389566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
13399566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
13409566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1341c5d2311dSJed Brown   }
13423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13433b224e63SBarry Smith }
13443b224e63SBarry Smith 
1345d484b384SBoris Martin /*
1346d484b384SBoris Martin   PCFieldSplitCreateWorkMats_Private - Allocate per-field dense work matrices for multi-RHS
1347d484b384SBoris Martin 
1348d484b384SBoris Martin   Input Parameters:
1349d484b384SBoris Martin + pc - the PC context
1350d484b384SBoris Martin - X  - matrix to copy column-layout from
1351d484b384SBoris Martin 
1352d484b384SBoris Martin   Notes:
1353d484b384SBoris Martin   If matrices already exist with correct column count, they are reused.
1354d484b384SBoris Martin   If column count changed, old matrices are destroyed and new ones created.
1355d484b384SBoris Martin */
PCFieldSplitCreateWorkMats_Private(PC pc,Mat X)1356d484b384SBoris Martin static PetscErrorCode PCFieldSplitCreateWorkMats_Private(PC pc, Mat X)
1357d484b384SBoris Martin {
1358d484b384SBoris Martin   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1359d484b384SBoris Martin   PC_FieldSplitLink ilink = jac->head;
1360d484b384SBoris Martin   PetscInt          mx, Mx, my, My, N;
1361d484b384SBoris Martin 
1362d484b384SBoris Martin   PetscFunctionBegin;
1363d484b384SBoris Martin   while (ilink) {
1364d484b384SBoris Martin     /* check if reallocation needed (previous allocation with wrong column count) */
1365d484b384SBoris Martin     if (ilink->X) {
1366d484b384SBoris Martin       PetscCall(MatGetSize(ilink->X, NULL, &N));
1367d484b384SBoris Martin       if (N != X->cmap->N) {
1368d484b384SBoris Martin         PetscCall(MatDestroy(&ilink->X));
1369d484b384SBoris Martin         PetscCall(MatDestroy(&ilink->Y));
1370f5b94327SPierre Jolivet         PetscCall(MatDestroy(&ilink->Z));
1371d484b384SBoris Martin       }
1372d484b384SBoris Martin     }
1373d484b384SBoris Martin     /* create if needed */
1374d484b384SBoris Martin     if (!ilink->X) {
1375d484b384SBoris Martin       VecType xtype, ytype;
1376d484b384SBoris Martin 
1377d484b384SBoris Martin       PetscCall(VecGetType(ilink->x, &xtype));
1378d484b384SBoris Martin       PetscCall(VecGetType(ilink->y, &ytype));
1379d484b384SBoris Martin       PetscCall(VecGetLocalSize(ilink->x, &mx));
1380d484b384SBoris Martin       PetscCall(VecGetSize(ilink->x, &Mx));
1381d484b384SBoris Martin       PetscCall(VecGetLocalSize(ilink->y, &my));
1382d484b384SBoris Martin       PetscCall(VecGetSize(ilink->y, &My));
1383d484b384SBoris Martin       /* use default lda */
1384d484b384SBoris Martin       PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), xtype, mx, X->cmap->n, Mx, X->cmap->N, -1, NULL, &ilink->X));
1385d484b384SBoris Martin       PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), ytype, my, X->cmap->n, My, X->cmap->N, -1, NULL, &ilink->Y));
1386d484b384SBoris Martin     }
1387d484b384SBoris Martin     ilink = ilink->next;
1388d484b384SBoris Martin   }
1389d484b384SBoris Martin   PetscFunctionReturn(PETSC_SUCCESS);
1390d484b384SBoris Martin }
1391d484b384SBoris Martin 
PCMatApply_FieldSplit_Schur(PC pc,Mat X,Mat Y)1392f5b94327SPierre Jolivet static PetscErrorCode PCMatApply_FieldSplit_Schur(PC pc, Mat X, Mat Y)
1393f5b94327SPierre Jolivet {
1394f5b94327SPierre Jolivet   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
1395f5b94327SPierre Jolivet   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1396f5b94327SPierre Jolivet   KSP               kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
1397f5b94327SPierre Jolivet   Mat               AinvB = NULL;
1398f5b94327SPierre Jolivet   PetscInt          N, P;
1399f5b94327SPierre Jolivet 
1400f5b94327SPierre Jolivet   PetscFunctionBegin;
1401f5b94327SPierre Jolivet   /* create working matrices with the correct number of columns */
1402f5b94327SPierre Jolivet   PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X));
1403f5b94327SPierre Jolivet   switch (jac->schurfactorization) {
1404f5b94327SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
1405f5b94327SPierre Jolivet     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
1406f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1407f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, INSERT_VALUES, SCATTER_FORWARD));
1408f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1409f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1410f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1411f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1412f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1413f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1414f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1415f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1416f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1417f5b94327SPierre Jolivet     PetscCall(MatScale(ilinkD->Y, jac->schurscale));
1418f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1419f5b94327SPierre Jolivet     break;
1420f5b94327SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
1421f5b94327SPierre Jolivet     /* [A00 0; A10 S], suitable for left preconditioning */
1422f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1423f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1424f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1425f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1426f5b94327SPierre Jolivet     PetscCall(MatMatMult(jac->C, ilinkA->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkD->X));
1427f5b94327SPierre Jolivet     PetscCall(MatScale(ilinkD->X, -1.0));
1428f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, ADD_VALUES, SCATTER_FORWARD));
1429f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1430f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1431f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1432f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1433f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1434f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1435f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1436f5b94327SPierre Jolivet     break;
1437f5b94327SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
1438f5b94327SPierre Jolivet     /* [A00 A01; 0 S], suitable for right preconditioning */
1439f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, INSERT_VALUES, SCATTER_FORWARD));
1440f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1441f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1442f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1443f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1444f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1445f5b94327SPierre Jolivet     PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1446f5b94327SPierre Jolivet     PetscCall(MatScale(ilinkA->X, -1.0));
1447f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, ADD_VALUES, SCATTER_FORWARD));
1448f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1449f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1450f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1451f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1452f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1453f5b94327SPierre Jolivet     break;
1454f5b94327SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
1455f5b94327SPierre Jolivet     /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */
1456f5b94327SPierre Jolivet     PetscCall(MatGetSize(jac->B, NULL, &P));
1457f5b94327SPierre Jolivet     N = P;
1458f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1459f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->X, ilinkA->Y, NULL));
1460f5b94327SPierre Jolivet     if (kspUpper == kspA) {
1461f5b94327SPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&AinvB));
1462f5b94327SPierre Jolivet       if (AinvB) {
1463f5b94327SPierre Jolivet         PetscCall(MatGetSize(AinvB, NULL, &N));
1464f5b94327SPierre Jolivet         if (N > P) { // first time PCApply_FieldSplit_Schur() is called
1465f5b94327SPierre Jolivet           PetscMemType mtype;
1466f5b94327SPierre Jolivet           Mat          C = NULL;
1467f5b94327SPierre Jolivet           PetscScalar *array;
1468f5b94327SPierre Jolivet           PetscInt     m, M, q, Q, p;
1469f5b94327SPierre Jolivet 
1470f5b94327SPierre Jolivet           PetscCall(MatGetSize(jac->B, &M, NULL));
1471f5b94327SPierre Jolivet           PetscCall(MatGetLocalSize(jac->B, &m, NULL));
1472f5b94327SPierre Jolivet           PetscCall(MatGetSize(X, NULL, &Q));
1473f5b94327SPierre Jolivet           PetscCall(MatGetLocalSize(X, NULL, &q));
1474f5b94327SPierre Jolivet           PetscCall(MatDenseGetArrayAndMemType(AinvB, &array, &mtype));
1475f5b94327SPierre Jolivet           if (N != P + Q) {
1476f5b94327SPierre Jolivet             Mat replace;
1477f5b94327SPierre Jolivet 
1478f5b94327SPierre Jolivet             PetscCall(MatGetLocalSize(jac->B, NULL, &p));
1479f5b94327SPierre Jolivet             if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) {
1480f5b94327SPierre Jolivet               PetscCall(PetscFree(array));
1481f5b94327SPierre Jolivet               PetscCall(PetscMalloc1(m * (P + Q), &array));
1482f5b94327SPierre Jolivet               PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1483f5b94327SPierre Jolivet             }
1484f5b94327SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1485f5b94327SPierre Jolivet             else if (PetscMemTypeCUDA(mtype)) {
1486f5b94327SPierre Jolivet               PetscCallCUDA(cudaFree(array));
1487f5b94327SPierre Jolivet               PetscCallCUDA(cudaMalloc((void **)&array, sizeof(PetscScalar) * m * (P + Q)));
1488f5b94327SPierre Jolivet               PetscCall(MatCreateDenseCUDA(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1489f5b94327SPierre Jolivet             }
1490f5b94327SPierre Jolivet #endif
1491f5b94327SPierre Jolivet #if PetscDefined(HAVE_HIP)
1492f5b94327SPierre Jolivet             else if (PetscMemTypeHIP(mtype)) {
1493f5b94327SPierre Jolivet               PetscCallHIP(hipFree(array));
1494f5b94327SPierre Jolivet               PetscCallHIP(hipMalloc((void **)&array, sizeof(PetscScalar) * m * (P + Q)));
1495f5b94327SPierre Jolivet               PetscCall(MatCreateDenseHIP(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1496f5b94327SPierre Jolivet             }
1497f5b94327SPierre Jolivet #endif
1498f5b94327SPierre Jolivet             PetscCall(MatHeaderReplace(AinvB, &replace));
1499f5b94327SPierre Jolivet           }
1500f5b94327SPierre Jolivet           if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1501f5b94327SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1502f5b94327SPierre Jolivet           else if (PetscMemTypeCUDA(mtype)) PetscCall(MatCreateDenseCUDA(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1503f5b94327SPierre Jolivet #endif
1504f5b94327SPierre Jolivet #if PetscDefined(HAVE_HIP)
1505f5b94327SPierre Jolivet           else if (PetscMemTypeHIP(mtype)) PetscCall(MatCreateDenseHIP(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1506f5b94327SPierre Jolivet #endif
1507f5b94327SPierre Jolivet           PetscCall(MatDenseRestoreArrayAndMemType(AinvB, &array));
1508f5b94327SPierre Jolivet           PetscCall(MatCopy(ilinkA->X, C, SAME_NONZERO_PATTERN));
1509f5b94327SPierre Jolivet           PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
1510f5b94327SPierre Jolivet           PetscCall(KSPSetOperators(jac->kspschur, jac->schur, jac->schur_user));
1511f5b94327SPierre Jolivet           PetscCall(MatCopy(C, ilinkA->Y, SAME_NONZERO_PATTERN)); // retrieve solutions as last columns of the composed Mat
1512f5b94327SPierre Jolivet           PetscCall(MatDestroy(&C));
1513f5b94327SPierre Jolivet         }
1514f5b94327SPierre Jolivet       }
1515f5b94327SPierre Jolivet     }
1516f5b94327SPierre Jolivet     if (N == P) PetscCall(KSPMatSolve(kspLower, ilinkA->X, ilinkA->Y));
1517f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->X, ilinkA->Y, NULL));
1518f5b94327SPierre Jolivet     PetscCall(MatMatMult(jac->C, ilinkA->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkD->X));
1519f5b94327SPierre Jolivet     PetscCall(MatScale(ilinkD->X, -1.0));
1520f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, ADD_VALUES, SCATTER_FORWARD));
1521f5b94327SPierre Jolivet 
1522f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1523f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1524f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1525f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1526f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1527f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1528f5b94327SPierre Jolivet 
1529f5b94327SPierre Jolivet     if (kspUpper == kspA) {
1530f5b94327SPierre Jolivet       if (!AinvB) {
1531f5b94327SPierre Jolivet         PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->Y));
1532f5b94327SPierre Jolivet         PetscCall(MatAXPY(ilinkA->X, -1.0, ilinkA->Y, SAME_NONZERO_PATTERN));
1533f5b94327SPierre Jolivet         PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1534f5b94327SPierre Jolivet         PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1535f5b94327SPierre Jolivet         PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1536f5b94327SPierre Jolivet       } else {
1537f5b94327SPierre Jolivet         PetscCall(MatMatMult(AinvB, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1538f5b94327SPierre Jolivet         PetscCall(MatAXPY(ilinkA->Y, 1.0, ilinkA->X, SAME_NONZERO_PATTERN));
1539f5b94327SPierre Jolivet       }
1540f5b94327SPierre Jolivet     } else {
1541f5b94327SPierre Jolivet       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1542f5b94327SPierre Jolivet       PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1543f5b94327SPierre Jolivet       PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1544f5b94327SPierre Jolivet       if (!ilinkA->Z) PetscCall(MatDuplicate(ilinkA->X, MAT_DO_NOT_COPY_VALUES, &ilinkA->Z));
1545f5b94327SPierre Jolivet       PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->X, ilinkA->Z, NULL));
1546f5b94327SPierre Jolivet       PetscCall(KSPMatSolve(kspUpper, ilinkA->X, ilinkA->Z));
1547f5b94327SPierre Jolivet       PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->X, ilinkA->Z, NULL));
1548f5b94327SPierre Jolivet       PetscCall(MatAXPY(ilinkA->Y, -1.0, ilinkA->Z, SAME_NONZERO_PATTERN));
1549f5b94327SPierre Jolivet     }
1550f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1551f5b94327SPierre Jolivet   }
1552f5b94327SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
1553f5b94327SPierre Jolivet }
1554f5b94327SPierre Jolivet 
PCApplyTranspose_FieldSplit_Schur(PC pc,Vec x,Vec y)15557b665727SPierre Jolivet static PetscErrorCode PCApplyTranspose_FieldSplit_Schur(PC pc, Vec x, Vec y)
15567b665727SPierre Jolivet {
15577b665727SPierre Jolivet   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
15587b665727SPierre Jolivet   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
15597b665727SPierre Jolivet   KSP               kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
15607b665727SPierre Jolivet 
15617b665727SPierre Jolivet   PetscFunctionBegin;
15627b665727SPierre Jolivet   switch (jac->schurfactorization) {
15637b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
15647b665727SPierre Jolivet     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
15657b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15667b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
15677b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15687b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15697b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
15707b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
15717b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15727b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15737b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
15747b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1575e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
15767b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1577e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
15787b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
15797b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
15807b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->y, jac->schurscale));
15817b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15827b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
15837b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
15847b665727SPierre Jolivet     break;
15857b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
15867b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15877b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15887b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15897b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
15907b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
15917b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15927b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x));
15937b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->x, -1.));
15947b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
15957b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15967b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
15977b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1598e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
15997b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1600e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
16017b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
16027b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
16037b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16047b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16057b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16067b665727SPierre Jolivet     break;
16077b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
16087b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
16097b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
16107b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1611e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
16127b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1613e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
16147b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
16157b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
16167b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x));
16177b665727SPierre Jolivet     PetscCall(VecScale(ilinkA->x, -1.));
16187b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
16197b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16207b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
16217b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16227b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16237b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16247b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16257b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16267b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16277b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16287b665727SPierre Jolivet     break;
16297b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
16307b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
16317b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
16327b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL));
16337b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspUpper, ilinkA->x, ilinkA->y));
16347b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->y));
16357b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL));
16367b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x));
16377b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->x, -1.0));
16387b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
16397b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
16407b665727SPierre Jolivet 
16417b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1642e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
16437b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1644e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
16457b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
16467b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
16477b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16487b665727SPierre Jolivet 
16497b665727SPierre Jolivet     if (kspLower == kspA) {
16507b665727SPierre Jolivet       PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->y));
16517b665727SPierre Jolivet       PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y));
16527b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16537b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16547b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16557b665727SPierre Jolivet       PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16567b665727SPierre Jolivet     } else {
16577b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16587b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16597b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16607b665727SPierre Jolivet       PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x));
16617b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL));
16627b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspLower, ilinkA->x, ilinkA->z));
16637b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->z));
16647b665727SPierre Jolivet       PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL));
16657b665727SPierre Jolivet       PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z));
16667b665727SPierre Jolivet     }
16677b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16687b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16697b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16707b665727SPierre Jolivet   }
16717b665727SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
16727b665727SPierre Jolivet }
16737b665727SPierre Jolivet 
16745becce15SPierre Jolivet #define FieldSplitSplitSolveAdd(ilink, xx, yy) \
16755becce15SPierre Jolivet   ((PetscErrorCode)(VecScatterBegin(ilink->sctx, xx, ilink->x, INSERT_VALUES, SCATTER_FORWARD) || VecScatterEnd(ilink->sctx, xx, ilink->x, INSERT_VALUES, SCATTER_FORWARD) || PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL) || \
16765becce15SPierre Jolivet                     KSPSolve(ilink->ksp, ilink->x, ilink->y) || KSPCheckSolve(ilink->ksp, pc, ilink->y) || PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL) || VecScatterBegin(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE) || \
16775becce15SPierre Jolivet                     VecScatterEnd(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE)))
16785becce15SPierre Jolivet 
PCApply_FieldSplit(PC pc,Vec x,Vec y)1679d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit(PC pc, Vec x, Vec y)
1680d71ae5a4SJacob Faibussowitsch {
16810971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
16825a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
1683939b8a20SBarry Smith   PetscInt          cnt, bs;
16840971522cSBarry Smith 
16850971522cSBarry Smith   PetscFunctionBegin;
168679416396SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
168780670ca5SBarry Smith     PetscBool matnest;
168880670ca5SBarry Smith 
168980670ca5SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
169080670ca5SBarry Smith     if (jac->defaultsplit && !matnest) {
16919566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(x, &bs));
16922472a847SBarry Smith       PetscCheck(jac->bs <= 0 || bs == jac->bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Blocksize of x vector %" PetscInt_FMT " does not match fieldsplit blocksize %" PetscInt_FMT, bs, jac->bs);
16939566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(y, &bs));
16942472a847SBarry Smith       PetscCheck(jac->bs <= 0 || bs == jac->bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Blocksize of y vector %" PetscInt_FMT " does not match fieldsplit blocksize %" PetscInt_FMT, bs, jac->bs);
16959566063dSJacob Faibussowitsch       PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
16965a9f2f41SSatish Balay       while (ilink) {
16979566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
16989566063dSJacob Faibussowitsch         PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
16999566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17009566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17015a9f2f41SSatish Balay         ilink = ilink->next;
17020971522cSBarry Smith       }
17039566063dSJacob Faibussowitsch       PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
17041b9fc7fcSBarry Smith     } else {
17059566063dSJacob Faibussowitsch       PetscCall(VecSet(y, 0.0));
17065a9f2f41SSatish Balay       while (ilink) {
17079566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
17085a9f2f41SSatish Balay         ilink = ilink->next;
17091b9fc7fcSBarry Smith       }
17101b9fc7fcSBarry Smith     }
1711e52d2c62SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
17129566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
1713e52d2c62SBarry Smith     /* solve on first block for first block variables */
17149566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
17159566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
17169566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17179566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17189566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17199566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17209566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17219566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1722e52d2c62SBarry Smith 
1723e52d2c62SBarry Smith     /* compute the residual only onto second block variables using first block variables */
17249566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->Afield[1], ilink->y, ilink->next->x));
1725e52d2c62SBarry Smith     ilink = ilink->next;
17269566063dSJacob Faibussowitsch     PetscCall(VecScale(ilink->x, -1.0));
17279566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17289566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1729e52d2c62SBarry Smith 
1730e52d2c62SBarry Smith     /* solve on second block variables */
17319566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17329566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17339566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17349566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17359566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17369566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
173716913363SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
173879416396SBarry Smith     if (!jac->w1) {
17399566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w1));
17409566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w2));
174179416396SBarry Smith     }
17429566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
17439566063dSJacob Faibussowitsch     PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
17443e197d65SBarry Smith     cnt = 1;
17455a9f2f41SSatish Balay     while (ilink->next) {
17465a9f2f41SSatish Balay       ilink = ilink->next;
17473e197d65SBarry Smith       /* compute the residual only over the part of the vector needed */
17489566063dSJacob Faibussowitsch       PetscCall(MatMult(jac->Afield[cnt++], y, ilink->x));
17499566063dSJacob Faibussowitsch       PetscCall(VecScale(ilink->x, -1.0));
17509566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17519566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17529566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17539566063dSJacob Faibussowitsch       PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17549566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17559566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17569566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17579566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17583e197d65SBarry Smith     }
175951f519a2SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
176011755939SBarry Smith       cnt -= 2;
176151f519a2SBarry Smith       while (ilink->previous) {
176251f519a2SBarry Smith         ilink = ilink->previous;
176311755939SBarry Smith         /* compute the residual only over the part of the vector needed */
17649566063dSJacob Faibussowitsch         PetscCall(MatMult(jac->Afield[cnt--], y, ilink->x));
17659566063dSJacob Faibussowitsch         PetscCall(VecScale(ilink->x, -1.0));
17669566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17679566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17689566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17699566063dSJacob Faibussowitsch         PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17709566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17719566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17729566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17739566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
177451f519a2SBarry Smith       }
177511755939SBarry Smith     }
177663a3b9bcSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)jac->type);
17773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17780971522cSBarry Smith }
17790971522cSBarry Smith 
PCMatApply_FieldSplit(PC pc,Mat X,Mat Y)1780d484b384SBoris Martin static PetscErrorCode PCMatApply_FieldSplit(PC pc, Mat X, Mat Y)
1781d484b384SBoris Martin {
1782d484b384SBoris Martin   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1783d484b384SBoris Martin   PC_FieldSplitLink ilink = jac->head;
1784d484b384SBoris Martin   PetscInt          cnt;
1785d484b384SBoris Martin 
1786d484b384SBoris Martin   PetscFunctionBegin;
1787d484b384SBoris Martin   /* create working matrices with the correct number of columns */
1788d484b384SBoris Martin   PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X));
1789d484b384SBoris Martin   if (jac->type == PC_COMPOSITE_ADDITIVE) {
1790d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
1791d484b384SBoris Martin     while (ilink) {
1792d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1793d484b384SBoris Martin       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1794d484b384SBoris Martin       PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1795d484b384SBoris Martin       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1796d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1797d484b384SBoris Martin       ilink = ilink->next;
1798d484b384SBoris Martin     }
1799d484b384SBoris Martin   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
1800d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
1801d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1802d484b384SBoris Martin     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1803d484b384SBoris Martin     PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1804d484b384SBoris Martin     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1805d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1806d484b384SBoris Martin 
1807d484b384SBoris Martin     /* compute the residual only onto second block variables using first block variables */
1808d484b384SBoris Martin     PetscCall(MatMatMult(jac->Afield[1], ilink->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->next->X));
1809d484b384SBoris Martin     ilink = ilink->next;
1810d484b384SBoris Martin     PetscCall(MatScale(ilink->X, -1.0));
1811d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1812d484b384SBoris Martin 
1813d484b384SBoris Martin     /* solve on second block variables */
1814d484b384SBoris Martin     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1815d484b384SBoris Martin     PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1816d484b384SBoris Martin     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1817d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1818d484b384SBoris Martin   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1819d484b384SBoris Martin     /* general multiplicative with any number of splits */
1820d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
1821d484b384SBoris Martin     /* first split */
1822d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1823d484b384SBoris Martin     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1824d484b384SBoris Martin     PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1825d484b384SBoris Martin     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1826d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1827d484b384SBoris Martin     cnt = 1;
1828d484b384SBoris Martin     /* forward sweep */
1829d484b384SBoris Martin     while (ilink->next) {
1830d484b384SBoris Martin       ilink = ilink->next;
1831d484b384SBoris Martin       /* compute the residual only over the part of the vector needed */
1832d484b384SBoris Martin       PetscCall(MatMatMult(jac->Afield[cnt++], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X));
1833d484b384SBoris Martin       PetscCall(MatScale(ilink->X, -1.0));
1834d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1835d484b384SBoris Martin       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1836d484b384SBoris Martin       PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1837d484b384SBoris Martin       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1838d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1839d484b384SBoris Martin     }
1840d484b384SBoris Martin     /* backward sweep for symmetric multiplicative */
1841d484b384SBoris Martin     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1842d484b384SBoris Martin       cnt -= 2;
1843d484b384SBoris Martin       while (ilink->previous) {
1844d484b384SBoris Martin         ilink = ilink->previous;
1845d484b384SBoris Martin         /* compute the residual only over the part of the vector needed */
1846d484b384SBoris Martin         PetscCall(MatMatMult(jac->Afield[cnt--], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X));
1847d484b384SBoris Martin         PetscCall(MatScale(ilink->X, -1.0));
1848d484b384SBoris Martin         PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1849d484b384SBoris Martin         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1850d484b384SBoris Martin         PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1851d484b384SBoris Martin         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1852d484b384SBoris Martin         PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1853d484b384SBoris Martin       }
1854d484b384SBoris Martin     }
1855d484b384SBoris Martin   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCMatApply() not implemented for this fieldsplit type");
1856d484b384SBoris Martin   PetscFunctionReturn(PETSC_SUCCESS);
1857d484b384SBoris Martin }
1858d484b384SBoris Martin 
PCApply_FieldSplit_GKB(PC pc,Vec x,Vec y)1859d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_GKB(PC pc, Vec x, Vec y)
1860d71ae5a4SJacob Faibussowitsch {
1861a51937d4SCarola Kruse   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
1862a51937d4SCarola Kruse   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1863a51937d4SCarola Kruse   KSP               ksp = ilinkA->ksp;
1864de482cd7SCarola Kruse   Vec               u, v, Hu, d, work1, work2;
1865e071a0a4SCarola Kruse   PetscScalar       alpha, z, nrmz2, *vecz;
1866e071a0a4SCarola Kruse   PetscReal         lowbnd, nu, beta;
1867a51937d4SCarola Kruse   PetscInt          j, iterGKB;
1868a51937d4SCarola Kruse 
1869a51937d4SCarola Kruse   PetscFunctionBegin;
18709566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
18719566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
18729566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
18739566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1874e071a0a4SCarola Kruse 
1875e071a0a4SCarola Kruse   u     = jac->u;
1876e071a0a4SCarola Kruse   v     = jac->v;
1877e071a0a4SCarola Kruse   Hu    = jac->Hu;
1878e071a0a4SCarola Kruse   d     = jac->d;
1879e071a0a4SCarola Kruse   work1 = jac->w1;
1880e071a0a4SCarola Kruse   work2 = jac->w2;
1881e071a0a4SCarola Kruse   vecz  = jac->vecz;
1882a51937d4SCarola Kruse 
1883a51937d4SCarola Kruse   /* Change RHS to comply with matrix regularization H = A + nu*B*B' */
1884a51937d4SCarola Kruse   /* Add q = q + nu*B*b */
1885a51937d4SCarola Kruse   if (jac->gkbnu) {
1886a51937d4SCarola Kruse     nu = jac->gkbnu;
18879566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->x, jac->gkbnu));
18889566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(jac->B, ilinkD->x, ilinkA->x, ilinkA->x)); /* q = q + nu*B*b */
1889a51937d4SCarola Kruse   } else {
1890a51937d4SCarola Kruse     /* Situation when no augmented Lagrangian is used. Then we set inner  */
1891a51937d4SCarola Kruse     /* matrix N = I in [Ar13], and thus nu = 1.                           */
1892a51937d4SCarola Kruse     nu = 1;
1893a51937d4SCarola Kruse   }
1894a51937d4SCarola Kruse 
1895a51937d4SCarola Kruse   /* Transform rhs from [q,tilde{b}] to [0,b] */
18969566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
18979566063dSJacob Faibussowitsch   PetscCall(KSPSolve(ksp, ilinkA->x, ilinkA->y));
18989566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(ksp, pc, ilinkA->y));
18999566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
19009566063dSJacob Faibussowitsch   PetscCall(MatMultHermitianTranspose(jac->B, ilinkA->y, work1));
19019566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(work1, 1.0 / nu, -1.0, ilinkD->x)); /* c = b - B'*x        */
1902a51937d4SCarola Kruse 
1903a51937d4SCarola Kruse   /* First step of algorithm */
19049566063dSJacob Faibussowitsch   PetscCall(VecNorm(work1, NORM_2, &beta)); /* beta = sqrt(nu*c'*c)*/
1905e071a0a4SCarola Kruse   KSPCheckDot(ksp, beta);
1906addd1e01SJunchao Zhang   beta = PetscSqrtReal(nu) * beta;
19079566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(v, nu / beta, 0.0, work1)); /* v = nu/beta *c      */
19089566063dSJacob Faibussowitsch   PetscCall(MatMult(jac->B, v, work2));          /* u = H^{-1}*B*v      */
19099566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
19109566063dSJacob Faibussowitsch   PetscCall(KSPSolve(ksp, work2, u));
19119566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(ksp, pc, u));
19129566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
19139566063dSJacob Faibussowitsch   PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u      */
19149566063dSJacob Faibussowitsch   PetscCall(VecDot(Hu, u, &alpha));
1915e071a0a4SCarola Kruse   KSPCheckDot(ksp, alpha);
191608401ef6SPierre Jolivet   PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1917addd1e01SJunchao Zhang   alpha = PetscSqrtReal(PetscAbsScalar(alpha));
19189566063dSJacob Faibussowitsch   PetscCall(VecScale(u, 1.0 / alpha));
19199566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(d, 1.0 / alpha, 0.0, v)); /* v = nu/beta *c      */
1920de482cd7SCarola Kruse 
1921a51937d4SCarola Kruse   z       = beta / alpha;
1922a51937d4SCarola Kruse   vecz[1] = z;
1923a51937d4SCarola Kruse 
1924de482cd7SCarola Kruse   /* Computation of first iterate x(1) and p(1) */
19259566063dSJacob Faibussowitsch   PetscCall(VecAXPY(ilinkA->y, z, u));
19269566063dSJacob Faibussowitsch   PetscCall(VecCopy(d, ilinkD->y));
19279566063dSJacob Faibussowitsch   PetscCall(VecScale(ilinkD->y, -z));
1928a51937d4SCarola Kruse 
19299371c9d4SSatish Balay   iterGKB = 1;
19309371c9d4SSatish Balay   lowbnd  = 2 * jac->gkbtol;
193148a46eb9SPierre Jolivet   if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1932de482cd7SCarola Kruse 
1933a51937d4SCarola Kruse   while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) {
1934a51937d4SCarola Kruse     iterGKB += 1;
19359566063dSJacob Faibussowitsch     PetscCall(MatMultHermitianTranspose(jac->B, u, work1)); /* v <- nu*(B'*u-alpha/nu*v) */
19369566063dSJacob Faibussowitsch     PetscCall(VecAXPBY(v, nu, -alpha, work1));
19379566063dSJacob Faibussowitsch     PetscCall(VecNorm(v, NORM_2, &beta)); /* beta = sqrt(nu)*v'*v      */
1938addd1e01SJunchao Zhang     beta = beta / PetscSqrtReal(nu);
19399566063dSJacob Faibussowitsch     PetscCall(VecScale(v, 1.0 / beta));
19409566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->B, v, work2)); /* u <- H^{-1}*(B*v-beta*H*u) */
19419566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, u, Hu));
19429566063dSJacob Faibussowitsch     PetscCall(VecAXPY(work2, -beta, Hu));
19439566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
19449566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ksp, work2, u));
19459566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ksp, pc, u));
19469566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
19479566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u            */
19489566063dSJacob Faibussowitsch     PetscCall(VecDot(Hu, u, &alpha));
1949e071a0a4SCarola Kruse     KSPCheckDot(ksp, alpha);
195008401ef6SPierre Jolivet     PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1951addd1e01SJunchao Zhang     alpha = PetscSqrtReal(PetscAbsScalar(alpha));
19529566063dSJacob Faibussowitsch     PetscCall(VecScale(u, 1.0 / alpha));
1953a51937d4SCarola Kruse 
1954e071a0a4SCarola Kruse     z       = -beta / alpha * z; /* z <- beta/alpha*z     */
1955a51937d4SCarola Kruse     vecz[0] = z;
1956a51937d4SCarola Kruse 
1957a51937d4SCarola Kruse     /* Computation of new iterate x(i+1) and p(i+1) */
19589566063dSJacob Faibussowitsch     PetscCall(VecAXPBY(d, 1.0 / alpha, -beta / alpha, v)); /* d = (v-beta*d)/alpha */
19599566063dSJacob Faibussowitsch     PetscCall(VecAXPY(ilinkA->y, z, u));                   /* r = r + z*u          */
19609566063dSJacob Faibussowitsch     PetscCall(VecAXPY(ilinkD->y, -z, d));                  /* p = p - z*d          */
19619566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, ilinkA->y, Hu));             /* ||u||_H = u'*H*u     */
19629566063dSJacob Faibussowitsch     PetscCall(VecDot(Hu, ilinkA->y, &nrmz2));
1963a51937d4SCarola Kruse 
1964a51937d4SCarola Kruse     /* Compute Lower Bound estimate */
1965a51937d4SCarola Kruse     if (iterGKB > jac->gkbdelay) {
1966a51937d4SCarola Kruse       lowbnd = 0.0;
1967ad540459SPierre Jolivet       for (j = 0; j < jac->gkbdelay; j++) lowbnd += PetscAbsScalar(vecz[j] * vecz[j]);
1968addd1e01SJunchao Zhang       lowbnd = PetscSqrtReal(lowbnd / PetscAbsScalar(nrmz2));
1969a51937d4SCarola Kruse     }
1970a51937d4SCarola Kruse 
1971ad540459SPierre Jolivet     for (j = 0; j < jac->gkbdelay - 1; j++) vecz[jac->gkbdelay - j - 1] = vecz[jac->gkbdelay - j - 2];
197248a46eb9SPierre Jolivet     if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1973a51937d4SCarola Kruse   }
1974a51937d4SCarola Kruse 
19759566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
19769566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
19779566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
19789566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
19793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1980a51937d4SCarola Kruse }
1981a51937d4SCarola Kruse 
1982421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink, xx, yy) \
19833ba16761SJacob Faibussowitsch   ((PetscErrorCode)(VecScatterBegin(ilink->sctx, xx, ilink->y, INSERT_VALUES, SCATTER_FORWARD) || VecScatterEnd(ilink->sctx, xx, ilink->y, INSERT_VALUES, SCATTER_FORWARD) || PetscLogEventBegin(ilink->event, ilink->ksp, ilink->y, ilink->x, NULL) || \
19849371c9d4SSatish Balay                     KSPSolveTranspose(ilink->ksp, ilink->y, ilink->x) || KSPCheckSolve(ilink->ksp, pc, ilink->x) || PetscLogEventEnd(ilink->event, ilink->ksp, ilink->y, ilink->x, NULL) || VecScatterBegin(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE) || \
19853ba16761SJacob Faibussowitsch                     VecScatterEnd(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE)))
1986421e10b8SBarry Smith 
PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)1987d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc, Vec x, Vec y)
1988d71ae5a4SJacob Faibussowitsch {
1989421e10b8SBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1990421e10b8SBarry Smith   PC_FieldSplitLink ilink = jac->head;
1991939b8a20SBarry Smith   PetscInt          bs;
1992421e10b8SBarry Smith 
1993421e10b8SBarry Smith   PetscFunctionBegin;
1994421e10b8SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
199580670ca5SBarry Smith     PetscBool matnest;
199680670ca5SBarry Smith 
199780670ca5SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
199880670ca5SBarry Smith     if (jac->defaultsplit && !matnest) {
19999566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(x, &bs));
20002472a847SBarry Smith       PetscCheck(jac->bs <= 0 || bs == jac->bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Blocksize of x vector %" PetscInt_FMT " does not match fieldsplit blocksize %" PetscInt_FMT, bs, jac->bs);
20019566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(y, &bs));
20022472a847SBarry Smith       PetscCheck(jac->bs <= 0 || bs == jac->bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Blocksize of y vector %" PetscInt_FMT " does not match fieldsplit blocksize %" PetscInt_FMT, bs, jac->bs);
20039566063dSJacob Faibussowitsch       PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
2004421e10b8SBarry Smith       while (ilink) {
20059566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
20069566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(ilink->ksp, ilink->x, ilink->y));
20079566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
20089566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
2009421e10b8SBarry Smith         ilink = ilink->next;
2010421e10b8SBarry Smith       }
20119566063dSJacob Faibussowitsch       PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
2012421e10b8SBarry Smith     } else {
20139566063dSJacob Faibussowitsch       PetscCall(VecSet(y, 0.0));
2014421e10b8SBarry Smith       while (ilink) {
20159566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2016421e10b8SBarry Smith         ilink = ilink->next;
2017421e10b8SBarry Smith       }
2018421e10b8SBarry Smith     }
2019421e10b8SBarry Smith   } else {
2020421e10b8SBarry Smith     if (!jac->w1) {
20219566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w1));
20229566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w2));
2023421e10b8SBarry Smith     }
20249566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
2025421e10b8SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
20269566063dSJacob Faibussowitsch       PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2027421e10b8SBarry Smith       while (ilink->next) {
2028421e10b8SBarry Smith         ilink = ilink->next;
20299566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20309566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20319566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2032421e10b8SBarry Smith       }
2033421e10b8SBarry Smith       while (ilink->previous) {
2034421e10b8SBarry Smith         ilink = ilink->previous;
20359566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20369566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20379566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2038421e10b8SBarry Smith       }
2039421e10b8SBarry Smith     } else {
2040421e10b8SBarry Smith       while (ilink->next) { /* get to last entry in linked list */
2041421e10b8SBarry Smith         ilink = ilink->next;
2042421e10b8SBarry Smith       }
20439566063dSJacob Faibussowitsch       PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2044421e10b8SBarry Smith       while (ilink->previous) {
2045421e10b8SBarry Smith         ilink = ilink->previous;
20469566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20479566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20489566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2049421e10b8SBarry Smith       }
2050421e10b8SBarry Smith     }
2051421e10b8SBarry Smith   }
20523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2053421e10b8SBarry Smith }
2054421e10b8SBarry Smith 
PCReset_FieldSplit(PC pc)2055d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_FieldSplit(PC pc)
2056d71ae5a4SJacob Faibussowitsch {
20570971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
20585a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head, next;
20590971522cSBarry Smith 
20600971522cSBarry Smith   PetscFunctionBegin;
20615a9f2f41SSatish Balay   while (ilink) {
20629566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&ilink->ksp));
20639566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->x));
20649566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->y));
20659566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->z));
2066d484b384SBoris Martin     PetscCall(MatDestroy(&ilink->X));
2067d484b384SBoris Martin     PetscCall(MatDestroy(&ilink->Y));
2068f5b94327SPierre Jolivet     PetscCall(MatDestroy(&ilink->Z));
20699566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&ilink->sctx));
20709566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is));
20719566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is_col));
20729566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->splitname));
20739566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->fields));
20749566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->fields_col));
20755a9f2f41SSatish Balay     next = ilink->next;
20769566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink));
20775a9f2f41SSatish Balay     ilink = next;
20780971522cSBarry Smith   }
2079f5f0d762SBarry Smith   jac->head = NULL;
20809566063dSJacob Faibussowitsch   PetscCall(PetscFree2(jac->x, jac->y));
2081574deadeSBarry Smith   if (jac->mat && jac->mat != jac->pmat) {
20829566063dSJacob Faibussowitsch     PetscCall(MatDestroyMatrices(jac->nsplits, &jac->mat));
2083574deadeSBarry Smith   } else if (jac->mat) {
20840298fd71SBarry Smith     jac->mat = NULL;
2085574deadeSBarry Smith   }
20869566063dSJacob Faibussowitsch   if (jac->pmat) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->pmat));
20879566063dSJacob Faibussowitsch   if (jac->Afield) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->Afield));
2088f5f0d762SBarry Smith   jac->nsplits = 0;
20899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->w1));
20909566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->w2));
209173716367SStefano Zampini   if (jac->schur) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", NULL));
20929566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schur));
20939566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schurp));
20949566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schur_user));
20959566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->kspschur));
20969566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->kspupper));
20979566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->B));
20989566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->C));
20999566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->H));
21009566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->u));
21019566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->v));
21029566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->Hu));
21039566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->d));
21049566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->vecz));
21059566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&jac->gkbviewer));
21066dbb499eSCian Wilson   jac->isrestrict = PETSC_FALSE;
21073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2108574deadeSBarry Smith }
2109574deadeSBarry Smith 
PCDestroy_FieldSplit(PC pc)2110d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_FieldSplit(PC pc)
2111d71ae5a4SJacob Faibussowitsch {
2112574deadeSBarry Smith   PetscFunctionBegin;
21139566063dSJacob Faibussowitsch   PetscCall(PCReset_FieldSplit(pc));
21149566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
21152e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL));
21169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", NULL));
21179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL));
21189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", NULL));
21199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", NULL));
21202e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", NULL));
21212e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", NULL));
21222e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
21232e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
21242e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
21252e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
21262e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
21279566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
21289566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
21299566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
21302e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
21313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21320971522cSBarry Smith }
21330971522cSBarry Smith 
PCSetFromOptions_FieldSplit(PC pc,PetscOptionItems PetscOptionsObject)2134ce78bad3SBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc, PetscOptionItems PetscOptionsObject)
2135d71ae5a4SJacob Faibussowitsch {
21366c924f48SJed Brown   PetscInt        bs;
21377b752e3dSPatrick Sanan   PetscBool       flg;
21389dcbbd2bSBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit *)pc->data;
21393b224e63SBarry Smith   PCCompositeType ctype;
21401b9fc7fcSBarry Smith 
21410971522cSBarry Smith   PetscFunctionBegin;
2142d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "FieldSplit options");
21439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_fieldsplit_dm_splits", "Whether to use DMCreateFieldDecomposition() for splits", "PCFieldSplitSetDMSplits", jac->dm_splits, &jac->dm_splits, NULL));
21449566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_fieldsplit_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", jac->bs, &bs, &flg));
21451baa6e33SBarry Smith   if (flg) PetscCall(PCFieldSplitSetBlockSize(pc, bs));
21462686e3e9SMatthew G. Knepley   jac->diag_use_amat = pc->useAmat;
21479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_fieldsplit_diag_use_amat", "Use Amat (not Pmat) to extract diagonal fieldsplit blocks", "PCFieldSplitSetDiagUseAmat", jac->diag_use_amat, &jac->diag_use_amat, NULL));
21482686e3e9SMatthew G. Knepley   jac->offdiag_use_amat = pc->useAmat;
21499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_fieldsplit_off_diag_use_amat", "Use Amat (not Pmat) to extract off-diagonal fieldsplit blocks", "PCFieldSplitSetOffDiagUseAmat", jac->offdiag_use_amat, &jac->offdiag_use_amat, NULL));
21509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_fieldsplit_detect_saddle_point", "Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint", jac->detect, &jac->detect, NULL));
21519566063dSJacob Faibussowitsch   PetscCall(PCFieldSplitSetDetectSaddlePoint(pc, jac->detect)); /* Sets split type and Schur PC type */
21529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_fieldsplit_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&ctype, &flg));
21531baa6e33SBarry Smith   if (flg) PetscCall(PCFieldSplitSetType(pc, ctype));
2154c30613efSMatthew Knepley   /* Only setup fields once */
2155b6555650SPierre Jolivet   if (jac->bs > 0 && jac->nsplits == 0) {
215680670ca5SBarry Smith     /* only allow user to set fields from command line.
2157d32f9abdSBarry Smith        otherwise user can set them in PCFieldSplitSetDefaults() */
21589566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc));
21599566063dSJacob Faibussowitsch     if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n"));
2160d32f9abdSBarry Smith   }
2161c5d2311dSJed Brown   if (jac->type == PC_COMPOSITE_SCHUR) {
21629566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetEnum(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_schur_factorization_type", PCFieldSplitSchurFactTypes, (PetscEnum *)&jac->schurfactorization, &flg));
21639566063dSJacob Faibussowitsch     if (flg) PetscCall(PetscInfo(pc, "Deprecated use of -pc_fieldsplit_schur_factorization_type\n"));
21649566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_fact_type", "Which off-diagonal parts of the block factorization to use", "PCFieldSplitSetSchurFactType", PCFieldSplitSchurFactTypes, (PetscEnum)jac->schurfactorization, (PetscEnum *)&jac->schurfactorization, NULL));
21659566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_precondition", "How to build preconditioner for Schur complement", "PCFieldSplitSetSchurPre", PCFieldSplitSchurPreTypes, (PetscEnum)jac->schurpre, (PetscEnum *)&jac->schurpre, NULL));
21669566063dSJacob Faibussowitsch     PetscCall(PetscOptionsScalar("-pc_fieldsplit_schur_scale", "Scale Schur complement", "PCFieldSplitSetSchurScale", jac->schurscale, &jac->schurscale, NULL));
2167a51937d4SCarola Kruse   } else if (jac->type == PC_COMPOSITE_GKB) {
2168a077d33dSBarry Smith     PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_tol", "The tolerance for the lower bound stopping criterion", "PCFieldSplitSetGKBTol", jac->gkbtol, &jac->gkbtol, NULL));
2169a077d33dSBarry Smith     PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_delay", "The delay value for lower bound criterion", "PCFieldSplitSetGKBDelay", jac->gkbdelay, &jac->gkbdelay, NULL));
2170a077d33dSBarry Smith     PetscCall(PetscOptionsBoundedReal("-pc_fieldsplit_gkb_nu", "Parameter in augmented Lagrangian approach", "PCFieldSplitSetGKBNu", jac->gkbnu, &jac->gkbnu, NULL, 0.0));
2171a077d33dSBarry Smith     PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_maxit", "Maximum allowed number of iterations", "PCFieldSplitSetGKBMaxit", jac->gkbmaxit, &jac->gkbmaxit, NULL));
21729566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-pc_fieldsplit_gkb_monitor", "Prints number of GKB iterations and error", "PCFieldSplitGKB", jac->gkbmonitor, &jac->gkbmonitor, NULL));
2173c5d2311dSJed Brown   }
217434603f55SBarry Smith   /*
217534603f55SBarry Smith     In the initial call to this routine the sub-solver data structures do not exist so we cannot call KSPSetFromOptions() on them yet.
217634603f55SBarry Smith     But after the initial setup of ALL the layers of sub-solvers is completed we do want to call KSPSetFromOptions() on the sub-solvers every time it
217734603f55SBarry Smith     is called on the outer solver in case changes were made in the options database
217834603f55SBarry Smith 
217934603f55SBarry Smith     But even after PCSetUp_FieldSplit() is called all the options inside the inner levels of sub-solvers may still not have been set thus we only call the KSPSetFromOptions()
218034603f55SBarry Smith     if we know that the entire stack of sub-solvers below this have been complete instantiated, we check this by seeing if any solver iterations are complete.
218134603f55SBarry Smith     Without this extra check test p2p1fetidp_olof_full and others fail with incorrect matrix types.
218234603f55SBarry Smith 
218334603f55SBarry Smith     There could be a negative side effect of calling the KSPSetFromOptions() below.
218434603f55SBarry Smith 
218534603f55SBarry Smith     If one captured the PetscObjectState of the options database one could skip these calls if the database has not changed from the previous call
218634603f55SBarry Smith   */
218734603f55SBarry Smith   if (jac->issetup) {
218834603f55SBarry Smith     PC_FieldSplitLink ilink = jac->head;
218934603f55SBarry Smith     if (jac->type == PC_COMPOSITE_SCHUR) {
219034603f55SBarry Smith       if (jac->kspupper && jac->kspupper->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspupper));
219134603f55SBarry Smith       if (jac->kspschur && jac->kspschur->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspschur));
219234603f55SBarry Smith     }
219334603f55SBarry Smith     while (ilink) {
219434603f55SBarry Smith       if (ilink->ksp->totalits > 0) PetscCall(KSPSetFromOptions(ilink->ksp));
219534603f55SBarry Smith       ilink = ilink->next;
219634603f55SBarry Smith     }
219734603f55SBarry Smith   }
2198d0609cedSBarry Smith   PetscOptionsHeadEnd();
21993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22000971522cSBarry Smith }
22010971522cSBarry Smith 
PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt * fields,const PetscInt * fields_col)2202d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col)
2203d71ae5a4SJacob Faibussowitsch {
220497bbdb24SBarry Smith   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
22055a9f2f41SSatish Balay   PC_FieldSplitLink ilink, next = jac->head;
220669a612a9SBarry Smith   char              prefix[128];
22075d4c12cdSJungho Lee   PetscInt          i;
2208835f2295SStefano Zampini   PetscLogEvent     nse;
22090971522cSBarry Smith 
22100971522cSBarry Smith   PetscFunctionBegin;
22116c924f48SJed Brown   if (jac->splitdefined) {
22129566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
22133ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
22146c924f48SJed Brown   }
2215ac530a7eSPierre Jolivet   for (i = 0; i < n; i++) PetscCheck(fields[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", fields[i]);
22169566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
2217a04f6461SBarry Smith   if (splitname) {
22189566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
2219a04f6461SBarry Smith   } else {
22209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(3, &ilink->splitname));
222163a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ilink->splitname, 2, "%" PetscInt_FMT, jac->nsplits));
2222a04f6461SBarry Smith   }
2223835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(jac->nsplits, &nse));
2224835f2295SStefano Zampini   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */
22259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &ilink->fields));
22269566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ilink->fields, fields, n));
22279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &ilink->fields_col));
22289566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ilink->fields_col, fields_col, n));
22292fa5cd67SKarl Rupp 
22305a9f2f41SSatish Balay   ilink->nfields = n;
22310298fd71SBarry Smith   ilink->next    = NULL;
22329566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
22333821be0aSBarry Smith   PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel));
22349566063dSJacob Faibussowitsch   PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
22359566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
22369566063dSJacob Faibussowitsch   PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
223769a612a9SBarry Smith 
22389566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
22399566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
22400971522cSBarry Smith 
22410971522cSBarry Smith   if (!next) {
22425a9f2f41SSatish Balay     jac->head       = ilink;
22430298fd71SBarry Smith     ilink->previous = NULL;
22440971522cSBarry Smith   } else {
2245ad540459SPierre Jolivet     while (next->next) next = next->next;
22465a9f2f41SSatish Balay     next->next      = ilink;
224751f519a2SBarry Smith     ilink->previous = next;
22480971522cSBarry Smith   }
22490971522cSBarry Smith   jac->nsplits++;
22503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22510971522cSBarry Smith }
22520971522cSBarry Smith 
PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc,PetscInt * n,KSP ** subksp)2253d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp)
2254d71ae5a4SJacob Faibussowitsch {
2255285fb4e2SStefano Zampini   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2256285fb4e2SStefano Zampini 
2257285fb4e2SStefano Zampini   PetscFunctionBegin;
2258285fb4e2SStefano Zampini   *subksp = NULL;
2259285fb4e2SStefano Zampini   if (n) *n = 0;
2260285fb4e2SStefano Zampini   if (jac->type == PC_COMPOSITE_SCHUR) {
2261285fb4e2SStefano Zampini     PetscInt nn;
2262285fb4e2SStefano Zampini 
226328b400f6SJacob Faibussowitsch     PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()");
226463a3b9bcSJacob Faibussowitsch     PetscCheck(jac->nsplits == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unexpected number of splits %" PetscInt_FMT " != 2", jac->nsplits);
2265285fb4e2SStefano Zampini     nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0);
22669566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nn, subksp));
2267285fb4e2SStefano Zampini     (*subksp)[0] = jac->head->ksp;
2268285fb4e2SStefano Zampini     (*subksp)[1] = jac->kspschur;
2269285fb4e2SStefano Zampini     if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper;
2270285fb4e2SStefano Zampini     if (n) *n = nn;
2271285fb4e2SStefano Zampini   }
22723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2273285fb4e2SStefano Zampini }
2274285fb4e2SStefano Zampini 
PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt * n,KSP ** subksp)2275d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc, PetscInt *n, KSP **subksp)
2276d71ae5a4SJacob Faibussowitsch {
2277e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2278e69d4d44SBarry Smith 
2279e69d4d44SBarry Smith   PetscFunctionBegin;
228028b400f6SJacob Faibussowitsch   PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()");
22819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(jac->nsplits, subksp));
22829566063dSJacob Faibussowitsch   PetscCall(MatSchurComplementGetKSP(jac->schur, *subksp));
22832fa5cd67SKarl Rupp 
2284e69d4d44SBarry Smith   (*subksp)[1] = jac->kspschur;
228513e0d083SBarry Smith   if (n) *n = jac->nsplits;
22863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2287e69d4d44SBarry Smith }
22880971522cSBarry Smith 
PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt * n,KSP ** subksp)2289d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp)
2290d71ae5a4SJacob Faibussowitsch {
22910971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
22920971522cSBarry Smith   PetscInt          cnt   = 0;
22935a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
22940971522cSBarry Smith 
22950971522cSBarry Smith   PetscFunctionBegin;
22969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(jac->nsplits, subksp));
22975a9f2f41SSatish Balay   while (ilink) {
22985a9f2f41SSatish Balay     (*subksp)[cnt++] = ilink->ksp;
22995a9f2f41SSatish Balay     ilink            = ilink->next;
23000971522cSBarry Smith   }
230163a3b9bcSJacob Faibussowitsch   PetscCheck(cnt == jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Corrupt PCFIELDSPLIT object: number of splits in linked list %" PetscInt_FMT " does not match number in object %" PetscInt_FMT, cnt, jac->nsplits);
230213e0d083SBarry Smith   if (n) *n = jac->nsplits;
23033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23040971522cSBarry Smith }
23050971522cSBarry Smith 
2306cc4c1da9SBarry Smith /*@
2307f1580f4eSBarry Smith   PCFieldSplitRestrictIS - Restricts the fieldsplit `IS`s to be within a given `IS`.
23086dbb499eSCian Wilson 
23096dbb499eSCian Wilson   Input Parameters:
23106dbb499eSCian Wilson + pc  - the preconditioner context
2311feefa0e1SJacob Faibussowitsch - isy - the index set that defines the indices to which the fieldsplit is to be restricted
23126dbb499eSCian Wilson 
23136dbb499eSCian Wilson   Level: advanced
23146dbb499eSCian Wilson 
2315feefa0e1SJacob Faibussowitsch   Developer Notes:
2316f1580f4eSBarry Smith   It seems the resulting `IS`s will not cover the entire space, so
2317f1580f4eSBarry Smith   how can they define a convergent preconditioner? Needs explaining.
2318f1580f4eSBarry Smith 
231960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
23206dbb499eSCian Wilson @*/
PCFieldSplitRestrictIS(PC pc,IS isy)2321d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitRestrictIS(PC pc, IS isy)
2322d71ae5a4SJacob Faibussowitsch {
23236dbb499eSCian Wilson   PetscFunctionBegin;
23246dbb499eSCian Wilson   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
23256dbb499eSCian Wilson   PetscValidHeaderSpecific(isy, IS_CLASSID, 2);
2326cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitRestrictIS_C", (PC, IS), (pc, isy));
23273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23286dbb499eSCian Wilson }
23296dbb499eSCian Wilson 
PCFieldSplitRestrictIS_FieldSplit(PC pc,IS isy)2330d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy)
2331d71ae5a4SJacob Faibussowitsch {
23326dbb499eSCian Wilson   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
23336dbb499eSCian Wilson   PC_FieldSplitLink ilink = jac->head, next;
23346dbb499eSCian Wilson   PetscInt          localsize, size, sizez, i;
23356dbb499eSCian Wilson   const PetscInt   *ind, *indz;
23366dbb499eSCian Wilson   PetscInt         *indc, *indcz;
23376dbb499eSCian Wilson   PetscBool         flg;
23386dbb499eSCian Wilson 
23396dbb499eSCian Wilson   PetscFunctionBegin;
23409566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isy, &localsize));
23419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Scan(&localsize, &size, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)isy)));
23426dbb499eSCian Wilson   size -= localsize;
23436dbb499eSCian Wilson   while (ilink) {
23446dbb499eSCian Wilson     IS isrl, isr;
23451c7cfba8SBarry Smith     PC subpc;
23469566063dSJacob Faibussowitsch     PetscCall(ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl));
23479566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(isrl, &localsize));
23489566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(localsize, &indc));
23499566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrl, &ind));
23509566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(indc, ind, localsize));
23519566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrl, &ind));
23529566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&isrl));
23536dbb499eSCian Wilson     for (i = 0; i < localsize; i++) *(indc + i) += size;
23549566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)isy), localsize, indc, PETSC_OWN_POINTER, &isr));
23559566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isr));
23569566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is));
23576dbb499eSCian Wilson     ilink->is = isr;
23589566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isr));
23599566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is_col));
23606dbb499eSCian Wilson     ilink->is_col = isr;
23619566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&isr));
23629566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(ilink->ksp, &subpc));
23639566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)subpc, PCFIELDSPLIT, &flg));
23646dbb499eSCian Wilson     if (flg) {
23656dbb499eSCian Wilson       IS       iszl, isz;
23666dbb499eSCian Wilson       MPI_Comm comm;
23679566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ilink->is, &localsize));
23686dbb499eSCian Wilson       comm = PetscObjectComm((PetscObject)ilink->is);
23699566063dSJacob Faibussowitsch       PetscCall(ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl));
23709566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Scan(&localsize, &sizez, 1, MPIU_INT, MPI_SUM, comm));
23716dbb499eSCian Wilson       sizez -= localsize;
23729566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(iszl, &localsize));
23739566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localsize, &indcz));
23749566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iszl, &indz));
23759566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(indcz, indz, localsize));
23769566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iszl, &indz));
23779566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&iszl));
23786dbb499eSCian Wilson       for (i = 0; i < localsize; i++) *(indcz + i) += sizez;
23799566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, localsize, indcz, PETSC_OWN_POINTER, &isz));
23809566063dSJacob Faibussowitsch       PetscCall(PCFieldSplitRestrictIS(subpc, isz));
23819566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isz));
23826dbb499eSCian Wilson     }
23836dbb499eSCian Wilson     next  = ilink->next;
23846dbb499eSCian Wilson     ilink = next;
23856dbb499eSCian Wilson   }
23866dbb499eSCian Wilson   jac->isrestrict = PETSC_TRUE;
23873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23886dbb499eSCian Wilson }
23896dbb499eSCian Wilson 
PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is)2390d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc, const char splitname[], IS is)
2391d71ae5a4SJacob Faibussowitsch {
2392704ba839SBarry Smith   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
2393704ba839SBarry Smith   PC_FieldSplitLink ilink, next = jac->head;
2394704ba839SBarry Smith   char              prefix[128];
2395835f2295SStefano Zampini   PetscLogEvent     nse;
2396704ba839SBarry Smith 
2397704ba839SBarry Smith   PetscFunctionBegin;
23986c924f48SJed Brown   if (jac->splitdefined) {
23999566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
24003ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
24016c924f48SJed Brown   }
24029566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
2403a04f6461SBarry Smith   if (splitname) {
24049566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
2405a04f6461SBarry Smith   } else {
24069566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(8, &ilink->splitname));
240763a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ilink->splitname, 7, "%" PetscInt_FMT, jac->nsplits));
2408a04f6461SBarry Smith   }
2409835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(jac->nsplits, &nse));
2410835f2295SStefano Zampini   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */
24119566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)is));
24129566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ilink->is));
2413b5787286SJed Brown   ilink->is = is;
24149566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)is));
24159566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ilink->is_col));
2416b5787286SJed Brown   ilink->is_col = is;
24170298fd71SBarry Smith   ilink->next   = NULL;
24189566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
24193821be0aSBarry Smith   PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel));
24209566063dSJacob Faibussowitsch   PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
24219566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
24229566063dSJacob Faibussowitsch   PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
2423704ba839SBarry Smith 
24249566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
24259566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
2426704ba839SBarry Smith 
2427704ba839SBarry Smith   if (!next) {
2428704ba839SBarry Smith     jac->head       = ilink;
24290298fd71SBarry Smith     ilink->previous = NULL;
2430704ba839SBarry Smith   } else {
2431ad540459SPierre Jolivet     while (next->next) next = next->next;
2432704ba839SBarry Smith     next->next      = ilink;
2433704ba839SBarry Smith     ilink->previous = next;
2434704ba839SBarry Smith   }
2435704ba839SBarry Smith   jac->nsplits++;
24363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2437704ba839SBarry Smith }
2438704ba839SBarry Smith 
24395d83a8b1SBarry Smith /*@
244060f59c3bSBarry Smith   PCFieldSplitSetFields - Sets the fields that define one particular split in `PCFIELDSPLIT`
24410971522cSBarry Smith 
2442c3339decSBarry Smith   Logically Collective
24430971522cSBarry Smith 
24440971522cSBarry Smith   Input Parameters:
24450971522cSBarry Smith + pc         - the preconditioner context
244660f59c3bSBarry Smith . splitname  - name of this split, if `NULL` the number of the split is used
24470971522cSBarry Smith . n          - the number of fields in this split
24483b374dbdSBarry Smith . fields     - the fields in this split
244980670ca5SBarry Smith - fields_col - generally the same as `fields`, if it does not match `fields` then the submatrix that is solved for this set of fields comes from an off-diagonal block
245080670ca5SBarry Smith                of the matrix and `fields_col` provides the column indices for that block
245180670ca5SBarry Smith 
245280670ca5SBarry Smith   Options Database Key:
245380670ca5SBarry Smith . -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split
24540971522cSBarry Smith 
24550971522cSBarry Smith   Level: intermediate
24560971522cSBarry Smith 
245795452b02SPatrick Sanan   Notes:
2458f1580f4eSBarry Smith   Use `PCFieldSplitSetIS()` to set a  general set of indices as a split.
2459d32f9abdSBarry Smith 
246080670ca5SBarry Smith   If the matrix used to construct the preconditioner is `MATNEST` then field i refers to the `is_row[i]` `IS` passed to `MatCreateNest()`.
246180670ca5SBarry Smith 
246280670ca5SBarry Smith   If the matrix used to construct the preconditioner is not `MATNEST` then
246354c05997SPierre Jolivet   `PCFieldSplitSetFields()` is for defining fields as strided blocks (based on the block size provided to the matrix with `MatSetBlockSize()` or
246480670ca5SBarry Smith   to the `PC` with `PCFieldSplitSetBlockSize()`). For example, if the block
2465f1580f4eSBarry Smith   size is three then one can define a split as 0, or 1 or 2 or 0,1 or 0,2 or 1,2 which mean
246614c74629SNuno Nobre   0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x23x56x8.. x12x45x78x....
2467f1580f4eSBarry Smith   where the numbered entries indicate what is in the split.
2468d32f9abdSBarry Smith 
2469db4c96c1SJed Brown   This function is called once per split (it creates a new split each time).  Solve options
247060f59c3bSBarry Smith   for this split will be available under the prefix `-fieldsplit_SPLITNAME_`.
2471db4c96c1SJed Brown 
247280670ca5SBarry Smith   `PCFieldSplitSetIS()` does not support having a `fields_col` different from `fields`
24733b374dbdSBarry Smith 
2474feefa0e1SJacob Faibussowitsch   Developer Notes:
2475f1580f4eSBarry Smith   This routine does not actually create the `IS` representing the split, that is delayed
2476f1580f4eSBarry Smith   until `PCSetUp_FieldSplit()`, because information about the vector/matrix layouts may not be
24775d4c12cdSJungho Lee   available when this routine is called.
24785d4c12cdSJungho Lee 
247980670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetIS()`, `PCFieldSplitRestrictIS()`,
248054c05997SPierre Jolivet           `MatSetBlockSize()`, `MatCreateNest()`
24810971522cSBarry Smith @*/
PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt fields[],const PetscInt fields_col[])2482cc4c1da9SBarry Smith PetscErrorCode PCFieldSplitSetFields(PC pc, const char splitname[], PetscInt n, const PetscInt fields[], const PetscInt fields_col[])
2483d71ae5a4SJacob Faibussowitsch {
24840971522cSBarry Smith   PetscFunctionBegin;
24850700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
24864f572ea9SToby Isaac   PetscAssertPointer(splitname, 2);
248763a3b9bcSJacob Faibussowitsch   PetscCheck(n >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, splitname);
24884f572ea9SToby Isaac   PetscAssertPointer(fields, 4);
2489cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetFields_C", (PC, const char[], PetscInt, const PetscInt *, const PetscInt *), (pc, splitname, n, fields, fields_col));
24903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24910971522cSBarry Smith }
24920971522cSBarry Smith 
2493c84da90fSDmitry Karpeev /*@
2494f1580f4eSBarry Smith   PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build
2495c14e9f00SDavid Andrs   the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2496c84da90fSDmitry Karpeev 
2497c3339decSBarry Smith   Logically Collective
2498c84da90fSDmitry Karpeev 
2499c84da90fSDmitry Karpeev   Input Parameters:
2500c84da90fSDmitry Karpeev + pc  - the preconditioner object
2501c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
2502c84da90fSDmitry Karpeev 
250320f4b53cSBarry Smith   Options Database Key:
2504147403d9SBarry Smith . -pc_fieldsplit_diag_use_amat - use the Amat to provide the diagonal blocks
2505c84da90fSDmitry Karpeev 
2506c84da90fSDmitry Karpeev   Level: intermediate
2507c84da90fSDmitry Karpeev 
250860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetDiagUseAmat()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFIELDSPLIT`
2509c84da90fSDmitry Karpeev @*/
PCFieldSplitSetDiagUseAmat(PC pc,PetscBool flg)2510d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc, PetscBool flg)
2511d71ae5a4SJacob Faibussowitsch {
2512c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2513c84da90fSDmitry Karpeev   PetscBool      isfs;
2514c84da90fSDmitry Karpeev 
2515c84da90fSDmitry Karpeev   PetscFunctionBegin;
2516c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25179566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
251828b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2519c84da90fSDmitry Karpeev   jac->diag_use_amat = flg;
25203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2521c84da90fSDmitry Karpeev }
2522c84da90fSDmitry Karpeev 
2523c84da90fSDmitry Karpeev /*@
2524f1580f4eSBarry Smith   PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build
2525c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2526c84da90fSDmitry Karpeev 
2527c3339decSBarry Smith   Logically Collective
2528c84da90fSDmitry Karpeev 
252920f4b53cSBarry Smith   Input Parameter:
2530c84da90fSDmitry Karpeev . pc - the preconditioner object
2531c84da90fSDmitry Karpeev 
253220f4b53cSBarry Smith   Output Parameter:
2533c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
2534c84da90fSDmitry Karpeev 
2535c84da90fSDmitry Karpeev   Level: intermediate
2536c84da90fSDmitry Karpeev 
253760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetDiagUseAmat()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFIELDSPLIT`
2538c84da90fSDmitry Karpeev @*/
PCFieldSplitGetDiagUseAmat(PC pc,PetscBool * flg)2539d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc, PetscBool *flg)
2540d71ae5a4SJacob Faibussowitsch {
2541c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2542c84da90fSDmitry Karpeev   PetscBool      isfs;
2543c84da90fSDmitry Karpeev 
2544c84da90fSDmitry Karpeev   PetscFunctionBegin;
2545c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25464f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
25479566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
254828b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2549c84da90fSDmitry Karpeev   *flg = jac->diag_use_amat;
25503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2551c84da90fSDmitry Karpeev }
2552c84da90fSDmitry Karpeev 
2553c84da90fSDmitry Karpeev /*@
2554f1580f4eSBarry Smith   PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build
2555c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2556c84da90fSDmitry Karpeev 
2557c3339decSBarry Smith   Logically Collective
2558c84da90fSDmitry Karpeev 
2559c84da90fSDmitry Karpeev   Input Parameters:
2560c84da90fSDmitry Karpeev + pc  - the preconditioner object
2561c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
2562c84da90fSDmitry Karpeev 
256320f4b53cSBarry Smith   Options Database Key:
2564147403d9SBarry Smith . -pc_fieldsplit_off_diag_use_amat <bool> - use the Amat to extract the off-diagonal blocks
2565c84da90fSDmitry Karpeev 
2566c84da90fSDmitry Karpeev   Level: intermediate
2567c84da90fSDmitry Karpeev 
256860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFieldSplitSetDiagUseAmat()`, `PCFIELDSPLIT`
2569c84da90fSDmitry Karpeev @*/
PCFieldSplitSetOffDiagUseAmat(PC pc,PetscBool flg)2570d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc, PetscBool flg)
2571d71ae5a4SJacob Faibussowitsch {
2572c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2573c84da90fSDmitry Karpeev   PetscBool      isfs;
2574c84da90fSDmitry Karpeev 
2575c84da90fSDmitry Karpeev   PetscFunctionBegin;
2576c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
257828b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2579c84da90fSDmitry Karpeev   jac->offdiag_use_amat = flg;
25803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2581c84da90fSDmitry Karpeev }
2582c84da90fSDmitry Karpeev 
2583c84da90fSDmitry Karpeev /*@
2584f1580f4eSBarry Smith   PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build
2585c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2586c84da90fSDmitry Karpeev 
2587c3339decSBarry Smith   Logically Collective
2588c84da90fSDmitry Karpeev 
258920f4b53cSBarry Smith   Input Parameter:
2590c84da90fSDmitry Karpeev . pc - the preconditioner object
2591c84da90fSDmitry Karpeev 
259220f4b53cSBarry Smith   Output Parameter:
2593c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
2594c84da90fSDmitry Karpeev 
2595c84da90fSDmitry Karpeev   Level: intermediate
2596c84da90fSDmitry Karpeev 
259760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFieldSplitGetDiagUseAmat()`, `PCFIELDSPLIT`
2598c84da90fSDmitry Karpeev @*/
PCFieldSplitGetOffDiagUseAmat(PC pc,PetscBool * flg)2599d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc, PetscBool *flg)
2600d71ae5a4SJacob Faibussowitsch {
2601c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2602c84da90fSDmitry Karpeev   PetscBool      isfs;
2603c84da90fSDmitry Karpeev 
2604c84da90fSDmitry Karpeev   PetscFunctionBegin;
2605c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26064f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
26079566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
260828b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2609c84da90fSDmitry Karpeev   *flg = jac->offdiag_use_amat;
26103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2611c84da90fSDmitry Karpeev }
2612c84da90fSDmitry Karpeev 
2613cc4c1da9SBarry Smith /*@
2614f1580f4eSBarry Smith   PCFieldSplitSetIS - Sets the exact elements for a split in a `PCFIELDSPLIT`
2615704ba839SBarry Smith 
2616c3339decSBarry Smith   Logically Collective
2617704ba839SBarry Smith 
2618704ba839SBarry Smith   Input Parameters:
2619704ba839SBarry Smith + pc        - the preconditioner context
262060f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used
2621f1580f4eSBarry Smith - is        - the index set that defines the elements in this split
2622704ba839SBarry Smith 
262360f59c3bSBarry Smith   Level: intermediate
262460f59c3bSBarry Smith 
2625a6ffb8dbSJed Brown   Notes:
262680670ca5SBarry Smith   Use `PCFieldSplitSetFields()`, for splits defined by strided `IS` based on the matrix block size or the `is_rows[]` passed into `MATNEST`
2627a6ffb8dbSJed Brown 
2628db4c96c1SJed Brown   This function is called once per split (it creates a new split each time).  Solve options
2629db4c96c1SJed Brown   for this split will be available under the prefix -fieldsplit_SPLITNAME_.
2630d32f9abdSBarry Smith 
263180670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetFields()`
2632704ba839SBarry Smith @*/
PCFieldSplitSetIS(PC pc,const char splitname[],IS is)2633d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetIS(PC pc, const char splitname[], IS is)
2634d71ae5a4SJacob Faibussowitsch {
2635704ba839SBarry Smith   PetscFunctionBegin;
26360700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26374f572ea9SToby Isaac   if (splitname) PetscAssertPointer(splitname, 2);
2638db4c96c1SJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
2639cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetIS_C", (PC, const char[], IS), (pc, splitname, is));
26403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2641704ba839SBarry Smith }
2642704ba839SBarry Smith 
2643cc4c1da9SBarry Smith /*@
2644f1580f4eSBarry Smith   PCFieldSplitGetIS - Retrieves the elements for a split as an `IS`
264557a9adfeSMatthew G Knepley 
2646c3339decSBarry Smith   Logically Collective
264757a9adfeSMatthew G Knepley 
264857a9adfeSMatthew G Knepley   Input Parameters:
264957a9adfeSMatthew G Knepley + pc        - the preconditioner context
265057a9adfeSMatthew G Knepley - splitname - name of this split
265157a9adfeSMatthew G Knepley 
265257a9adfeSMatthew G Knepley   Output Parameter:
2653feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split, or `NULL` if the split is not found
265457a9adfeSMatthew G Knepley 
265557a9adfeSMatthew G Knepley   Level: intermediate
265657a9adfeSMatthew G Knepley 
265780670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetIS()`, `PCFieldSplitGetISByIndex()`
265857a9adfeSMatthew G Knepley @*/
PCFieldSplitGetIS(PC pc,const char splitname[],IS * is)2659d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetIS(PC pc, const char splitname[], IS *is)
2660d71ae5a4SJacob Faibussowitsch {
266157a9adfeSMatthew G Knepley   PetscFunctionBegin;
266257a9adfeSMatthew G Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26634f572ea9SToby Isaac   PetscAssertPointer(splitname, 2);
26644f572ea9SToby Isaac   PetscAssertPointer(is, 3);
266557a9adfeSMatthew G Knepley   {
266657a9adfeSMatthew G Knepley     PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
266757a9adfeSMatthew G Knepley     PC_FieldSplitLink ilink = jac->head;
266857a9adfeSMatthew G Knepley     PetscBool         found;
266957a9adfeSMatthew G Knepley 
26700298fd71SBarry Smith     *is = NULL;
267157a9adfeSMatthew G Knepley     while (ilink) {
26729566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(ilink->splitname, splitname, &found));
267357a9adfeSMatthew G Knepley       if (found) {
267457a9adfeSMatthew G Knepley         *is = ilink->is;
267557a9adfeSMatthew G Knepley         break;
267657a9adfeSMatthew G Knepley       }
267757a9adfeSMatthew G Knepley       ilink = ilink->next;
267857a9adfeSMatthew G Knepley     }
267957a9adfeSMatthew G Knepley   }
26803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
268157a9adfeSMatthew G Knepley }
268257a9adfeSMatthew G Knepley 
2683cc4c1da9SBarry Smith /*@
2684f1580f4eSBarry Smith   PCFieldSplitGetISByIndex - Retrieves the elements for a given split as an `IS`
2685998f007dSPierre Jolivet 
2686c3339decSBarry Smith   Logically Collective
2687998f007dSPierre Jolivet 
2688998f007dSPierre Jolivet   Input Parameters:
2689998f007dSPierre Jolivet + pc    - the preconditioner context
2690998f007dSPierre Jolivet - index - index of this split
2691998f007dSPierre Jolivet 
2692998f007dSPierre Jolivet   Output Parameter:
2693feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split
2694998f007dSPierre Jolivet 
2695998f007dSPierre Jolivet   Level: intermediate
2696998f007dSPierre Jolivet 
269780670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitGetIS()`, `PCFieldSplitSetIS()`,
269880670ca5SBarry Smith 
2699998f007dSPierre Jolivet @*/
PCFieldSplitGetISByIndex(PC pc,PetscInt index,IS * is)2700d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetISByIndex(PC pc, PetscInt index, IS *is)
2701d71ae5a4SJacob Faibussowitsch {
2702998f007dSPierre Jolivet   PetscFunctionBegin;
270363a3b9bcSJacob Faibussowitsch   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", index);
2704998f007dSPierre Jolivet   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
27054f572ea9SToby Isaac   PetscAssertPointer(is, 3);
2706998f007dSPierre Jolivet   {
2707998f007dSPierre Jolivet     PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
2708998f007dSPierre Jolivet     PC_FieldSplitLink ilink = jac->head;
2709998f007dSPierre Jolivet     PetscInt          i     = 0;
271063a3b9bcSJacob Faibussowitsch     PetscCheck(index < jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", index, jac->nsplits);
2711998f007dSPierre Jolivet 
2712998f007dSPierre Jolivet     while (i < index) {
2713998f007dSPierre Jolivet       ilink = ilink->next;
2714998f007dSPierre Jolivet       ++i;
2715998f007dSPierre Jolivet     }
27169566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitGetIS(pc, ilink->splitname, is));
2717998f007dSPierre Jolivet   }
27183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2719998f007dSPierre Jolivet }
2720998f007dSPierre Jolivet 
272151f519a2SBarry Smith /*@
272251f519a2SBarry Smith   PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
272380670ca5SBarry Smith   fieldsplit preconditioner when calling `PCFieldSplitSetFields()`. If not set the matrix block size is used.
272451f519a2SBarry Smith 
2725c3339decSBarry Smith   Logically Collective
272651f519a2SBarry Smith 
272751f519a2SBarry Smith   Input Parameters:
272851f519a2SBarry Smith + pc - the preconditioner context
272951f519a2SBarry Smith - bs - the block size
273051f519a2SBarry Smith 
273151f519a2SBarry Smith   Level: intermediate
273251f519a2SBarry Smith 
273380670ca5SBarry Smith   Note:
273480670ca5SBarry Smith   If the matrix is a `MATNEST` then the `is_rows[]` passed to `MatCreateNest()` determines the fields.
273580670ca5SBarry Smith 
273660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
273751f519a2SBarry Smith @*/
PCFieldSplitSetBlockSize(PC pc,PetscInt bs)2738d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetBlockSize(PC pc, PetscInt bs)
2739d71ae5a4SJacob Faibussowitsch {
274051f519a2SBarry Smith   PetscFunctionBegin;
27410700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2742c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, bs, 2);
2743cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetBlockSize_C", (PC, PetscInt), (pc, bs));
27443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
274551f519a2SBarry Smith }
274651f519a2SBarry Smith 
27470971522cSBarry Smith /*@C
2748f1580f4eSBarry Smith   PCFieldSplitGetSubKSP - Gets the `KSP` contexts for all splits
27490971522cSBarry Smith 
2750c3339decSBarry Smith   Collective
27510971522cSBarry Smith 
27520971522cSBarry Smith   Input Parameter:
27530971522cSBarry Smith . pc - the preconditioner context
27540971522cSBarry Smith 
27550971522cSBarry Smith   Output Parameters:
275613e0d083SBarry Smith + n      - the number of splits
2757f1580f4eSBarry Smith - subksp - the array of `KSP` contexts
2758196cc216SBarry Smith 
27590971522cSBarry Smith   Level: advanced
27600971522cSBarry Smith 
2761f1580f4eSBarry Smith   Notes:
2762f1580f4eSBarry Smith   After `PCFieldSplitGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()`
2763f1580f4eSBarry Smith   (not the `KSP`, just the array that contains them).
2764f1580f4eSBarry Smith 
2765f1580f4eSBarry Smith   You must call `PCSetUp()` before calling `PCFieldSplitGetSubKSP()`.
2766f1580f4eSBarry Smith 
2767f1580f4eSBarry Smith   If the fieldsplit is of type `PC_COMPOSITE_SCHUR`, it returns the `KSP` object used inside the
2768f1580f4eSBarry Smith   Schur complement and the `KSP` object used to iterate over the Schur complement.
2769f1580f4eSBarry Smith   To access all the `KSP` objects used in `PC_COMPOSITE_SCHUR`, use `PCFieldSplitSchurGetSubKSP()`.
2770f1580f4eSBarry Smith 
2771f1580f4eSBarry Smith   If the fieldsplit is of type `PC_COMPOSITE_GKB`, it returns the `KSP` object used to solve the
2772f1580f4eSBarry Smith   inner linear system defined by the matrix H in each loop.
2773f1580f4eSBarry Smith 
2774feaf08eaSBarry Smith   Fortran Note:
2775e41f517fSBarry Smith   Call `PCFieldSplitRestoreSubKSP()` when the array of `KSP` is no longer needed
2776f1580f4eSBarry Smith 
2777feefa0e1SJacob Faibussowitsch   Developer Notes:
2778f1580f4eSBarry Smith   There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()`
2779f1580f4eSBarry Smith 
278060f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitSchurGetSubKSP()`
27810971522cSBarry Smith @*/
PCFieldSplitGetSubKSP(PC pc,PetscInt * n,KSP * subksp[])2782d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSubKSP(PC pc, PetscInt *n, KSP *subksp[])
2783d71ae5a4SJacob Faibussowitsch {
27840971522cSBarry Smith   PetscFunctionBegin;
27850700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
27864f572ea9SToby Isaac   if (n) PetscAssertPointer(n, 2);
2787cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
27883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27890971522cSBarry Smith }
27900971522cSBarry Smith 
2791285fb4e2SStefano Zampini /*@C
2792f1580f4eSBarry Smith   PCFieldSplitSchurGetSubKSP - Gets the `KSP` contexts used inside the Schur complement based `PCFIELDSPLIT`
2793285fb4e2SStefano Zampini 
279460f59c3bSBarry Smith   Collective
2795285fb4e2SStefano Zampini 
2796285fb4e2SStefano Zampini   Input Parameter:
2797285fb4e2SStefano Zampini . pc - the preconditioner context
2798285fb4e2SStefano Zampini 
2799285fb4e2SStefano Zampini   Output Parameters:
2800285fb4e2SStefano Zampini + n      - the number of splits
2801f1580f4eSBarry Smith - subksp - the array of `KSP` contexts
2802285fb4e2SStefano Zampini 
2803285fb4e2SStefano Zampini   Level: advanced
2804285fb4e2SStefano Zampini 
2805f1580f4eSBarry Smith   Notes:
2806f1580f4eSBarry Smith   After `PCFieldSplitSchurGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()`
2807f1580f4eSBarry Smith   (not the `KSP` just the array that contains them).
2808f1580f4eSBarry Smith 
2809f1580f4eSBarry Smith   You must call `PCSetUp()` before calling `PCFieldSplitSchurGetSubKSP()`.
2810f1580f4eSBarry Smith 
2811f1580f4eSBarry Smith   If the fieldsplit type is of type `PC_COMPOSITE_SCHUR`, it returns (in order)
2812f1580f4eSBarry Smith +  1  - the `KSP` used for the (1,1) block
2813f1580f4eSBarry Smith .  2  - the `KSP` used for the Schur complement (not the one used for the interior Schur solver)
2814f1580f4eSBarry Smith -  3  - the `KSP` used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block).
2815f1580f4eSBarry Smith 
2816f1580f4eSBarry Smith   It returns a null array if the fieldsplit is not of type `PC_COMPOSITE_SCHUR`; in this case, you should use `PCFieldSplitGetSubKSP()`.
2817f1580f4eSBarry Smith 
2818feaf08eaSBarry Smith   Fortran Note:
2819e41f517fSBarry Smith   Call `PCFieldSplitSchurRestoreSubKSP()` when the array of `KSP` is no longer needed
2820f1580f4eSBarry Smith 
2821f1580f4eSBarry Smith   Developer Notes:
2822f1580f4eSBarry Smith   There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()`
2823f1580f4eSBarry Smith 
2824f1580f4eSBarry Smith   Should the functionality of `PCFieldSplitSchurGetSubKSP()` and `PCFieldSplitGetSubKSP()` be merged?
2825f1580f4eSBarry Smith 
282660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitGetSubKSP()`
2827285fb4e2SStefano Zampini @*/
PCFieldSplitSchurGetSubKSP(PC pc,PetscInt * n,KSP * subksp[])2828d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc, PetscInt *n, KSP *subksp[])
2829d71ae5a4SJacob Faibussowitsch {
2830285fb4e2SStefano Zampini   PetscFunctionBegin;
2831285fb4e2SStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
28324f572ea9SToby Isaac   if (n) PetscAssertPointer(n, 2);
2833cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitSchurGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
28343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2835285fb4e2SStefano Zampini }
2836285fb4e2SStefano Zampini 
2837e69d4d44SBarry Smith /*@
2838c14e9f00SDavid Andrs   PCFieldSplitSetSchurPre -  Indicates from what operator the preconditioner is constructed for the Schur complement.
2839a1e3cbf9SBarry Smith   The default is the A11 matrix.
2840e69d4d44SBarry Smith 
2841c3339decSBarry Smith   Collective
2842e69d4d44SBarry Smith 
2843e69d4d44SBarry Smith   Input Parameters:
2844e69d4d44SBarry Smith + pc    - the preconditioner context
2845f1580f4eSBarry Smith . ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11` (default),
2846f1580f4eSBarry Smith               `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER`,
2847f1580f4eSBarry Smith               `PC_FIELDSPLIT_SCHUR_PRE_SELFP`, and `PC_FIELDSPLIT_SCHUR_PRE_FULL`
284860f59c3bSBarry Smith - pre   - matrix to use for preconditioning, or `NULL`
2849084e4875SJed Brown 
2850f1580f4eSBarry Smith   Options Database Keys:
2851d59693daSPierre Jolivet + -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`. See notes for meaning of various arguments
2852a1e3cbf9SBarry Smith - -fieldsplit_1_pc_type <pctype>                               - the preconditioner algorithm that is used to construct the preconditioner from the operator
2853e69d4d44SBarry Smith 
285460f59c3bSBarry Smith   Level: intermediate
285560f59c3bSBarry Smith 
2856fd1303e9SJungho Lee   Notes:
2857f1580f4eSBarry Smith   If ptype is
2858f1580f4eSBarry Smith +     a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner
2859f1580f4eSBarry Smith   matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix
2860f1580f4eSBarry Smith .     self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix:
2861e7593814SPierre Jolivet   The only preconditioners that currently work with this symbolic representation matrix object are `PCLSC` and `PCHPDDM`
2862f1580f4eSBarry Smith .     user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument
2863f1580f4eSBarry Smith   to this function).
2864a077d33dSBarry Smith .     selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation $ Sp = A11 - A10 inv(diag(A00)) A01 $
2865f1580f4eSBarry Smith   This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be
2866d59693daSPierre Jolivet   lumped before extracting the diagonal using the additional option `-fieldsplit_1_mat_schur_complement_ainv_type lump`
2867f1580f4eSBarry Smith -     full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation
2868f1580f4eSBarry Smith   computed internally by `PCFIELDSPLIT` (this is expensive)
2869f1580f4eSBarry Smith   useful mostly as a test that the Schur complement approach can work for your problem
2870fd1303e9SJungho Lee 
2871d59693daSPierre Jolivet   When solving a saddle point problem, where the A11 block is identically zero, using `a11` as the ptype only makes sense
2872a077d33dSBarry Smith   with the additional option `-fieldsplit_1_pc_type none`. Usually for saddle point problems one would use a `ptype` of `self` and
2873d59693daSPierre Jolivet   `-fieldsplit_1_pc_type lsc` which uses the least squares commutator to compute a preconditioner for the Schur complement.
2874fd1303e9SJungho Lee 
2875a077d33dSBarry Smith   Developer Note:
2876a077d33dSBarry Smith   The name of this function and the option `-pc_fieldsplit_schur_precondition` are inconsistent; precondition should be used everywhere.
2877feefa0e1SJacob Faibussowitsch 
2878a077d33dSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`,
2879a077d33dSBarry Smith           `MatSchurComplementSetAinvType()`, `PCLSC`, `PCFieldSplitSetSchurFactType()`
2880e69d4d44SBarry Smith @*/
PCFieldSplitSetSchurPre(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)2881d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurPre(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2882d71ae5a4SJacob Faibussowitsch {
2883e69d4d44SBarry Smith   PetscFunctionBegin;
28840700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2885cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurPre_C", (PC, PCFieldSplitSchurPreType, Mat), (pc, ptype, pre));
28863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2887e69d4d44SBarry Smith }
2888686bed4dSStefano Zampini 
PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)2889d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurPrecondition(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2890d71ae5a4SJacob Faibussowitsch {
28919371c9d4SSatish Balay   return PCFieldSplitSetSchurPre(pc, ptype, pre);
28929371c9d4SSatish Balay } /* Deprecated name */
2893e69d4d44SBarry Smith 
289437a82bf0SJed Brown /*@
289537a82bf0SJed Brown   PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be
2896f1580f4eSBarry Smith   preconditioned.  See `PCFieldSplitSetSchurPre()` for details.
289737a82bf0SJed Brown 
2898c3339decSBarry Smith   Logically Collective
289937a82bf0SJed Brown 
2900f899ff85SJose E. Roman   Input Parameter:
290137a82bf0SJed Brown . pc - the preconditioner context
290237a82bf0SJed Brown 
290337a82bf0SJed Brown   Output Parameters:
2904d59693daSPierre Jolivet + ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11`, `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER`
2905d59693daSPierre Jolivet - pre   - matrix to use for preconditioning (with `PC_FIELDSPLIT_SCHUR_PRE_USER`), or `NULL`
290637a82bf0SJed Brown 
290737a82bf0SJed Brown   Level: intermediate
290837a82bf0SJed Brown 
2909d59693daSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCLSC`
291037a82bf0SJed Brown @*/
PCFieldSplitGetSchurPre(PC pc,PCFieldSplitSchurPreType * ptype,Mat * pre)2911d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurPre(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre)
2912d71ae5a4SJacob Faibussowitsch {
291337a82bf0SJed Brown   PetscFunctionBegin;
291437a82bf0SJed Brown   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2915cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitGetSchurPre_C", (PC, PCFieldSplitSchurPreType *, Mat *), (pc, ptype, pre));
29163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2917e69d4d44SBarry Smith }
2918e69d4d44SBarry Smith 
291945e7fc46SDmitry Karpeev /*@
2920f1580f4eSBarry Smith   PCFieldSplitSchurGetS -  extract the `MATSCHURCOMPLEMENT` object used by this `PCFIELDSPLIT` in case it needs to be configured separately
292145e7fc46SDmitry Karpeev 
292220f4b53cSBarry Smith   Not Collective
292345e7fc46SDmitry Karpeev 
292445e7fc46SDmitry Karpeev   Input Parameter:
292545e7fc46SDmitry Karpeev . pc - the preconditioner context
292645e7fc46SDmitry Karpeev 
292745e7fc46SDmitry Karpeev   Output Parameter:
2928470b340bSDmitry Karpeev . S - the Schur complement matrix
292945e7fc46SDmitry Karpeev 
293060f59c3bSBarry Smith   Level: advanced
293160f59c3bSBarry Smith 
2932f1580f4eSBarry Smith   Note:
2933f1580f4eSBarry Smith   This matrix should not be destroyed using `MatDestroy()`; rather, use `PCFieldSplitSchurRestoreS()`.
293445e7fc46SDmitry Karpeev 
293560f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MATSCHURCOMPLEMENT`, `PCFieldSplitSchurRestoreS()`,
2936f1580f4eSBarry Smith           `MatCreateSchurComplement()`, `MatSchurComplementGetKSP()`, `MatSchurComplementComputeExplicitOperator()`, `MatGetSchurComplement()`
293745e7fc46SDmitry Karpeev @*/
PCFieldSplitSchurGetS(PC pc,Mat * S)2938d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetS(PC pc, Mat *S)
2939d71ae5a4SJacob Faibussowitsch {
294045e7fc46SDmitry Karpeev   const char    *t;
294145e7fc46SDmitry Karpeev   PetscBool      isfs;
294245e7fc46SDmitry Karpeev   PC_FieldSplit *jac;
294345e7fc46SDmitry Karpeev 
294445e7fc46SDmitry Karpeev   PetscFunctionBegin;
294545e7fc46SDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
29469566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetType((PetscObject)pc, &t));
29479566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
294828b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
294945e7fc46SDmitry Karpeev   jac = (PC_FieldSplit *)pc->data;
295063a3b9bcSJacob Faibussowitsch   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
2951470b340bSDmitry Karpeev   if (S) *S = jac->schur;
29523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
295345e7fc46SDmitry Karpeev }
295445e7fc46SDmitry Karpeev 
2955470b340bSDmitry Karpeev /*@
2956f1580f4eSBarry Smith   PCFieldSplitSchurRestoreS -  returns the `MATSCHURCOMPLEMENT` matrix used by this `PC`
2957470b340bSDmitry Karpeev 
295820f4b53cSBarry Smith   Not Collective
2959470b340bSDmitry Karpeev 
2960470b340bSDmitry Karpeev   Input Parameters:
2961470b340bSDmitry Karpeev + pc - the preconditioner context
2962a2b725a8SWilliam Gropp - S  - the Schur complement matrix
2963470b340bSDmitry Karpeev 
2964470b340bSDmitry Karpeev   Level: advanced
2965470b340bSDmitry Karpeev 
296660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurGetS()`
2967470b340bSDmitry Karpeev @*/
PCFieldSplitSchurRestoreS(PC pc,Mat * S)2968d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurRestoreS(PC pc, Mat *S)
2969d71ae5a4SJacob Faibussowitsch {
2970470b340bSDmitry Karpeev   const char    *t;
2971470b340bSDmitry Karpeev   PetscBool      isfs;
2972470b340bSDmitry Karpeev   PC_FieldSplit *jac;
2973470b340bSDmitry Karpeev 
2974470b340bSDmitry Karpeev   PetscFunctionBegin;
2975470b340bSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
29769566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetType((PetscObject)pc, &t));
29779566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
297828b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
2979470b340bSDmitry Karpeev   jac = (PC_FieldSplit *)pc->data;
298063a3b9bcSJacob Faibussowitsch   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
29817827d75bSBarry Smith   PetscCheck(S && (*S == jac->schur), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatSchurComplement restored is not the same as gotten");
29823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2983470b340bSDmitry Karpeev }
2984470b340bSDmitry Karpeev 
PCFieldSplitSetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)2985d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2986d71ae5a4SJacob Faibussowitsch {
2987e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2988e69d4d44SBarry Smith 
2989e69d4d44SBarry Smith   PetscFunctionBegin;
2990084e4875SJed Brown   jac->schurpre = ptype;
2991a7476a74SDmitry Karpeev   if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) {
29929566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&jac->schur_user));
2993084e4875SJed Brown     jac->schur_user = pre;
29949566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)jac->schur_user));
2995084e4875SJed Brown   }
29963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2997e69d4d44SBarry Smith }
2998e69d4d44SBarry Smith 
PCFieldSplitGetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType * ptype,Mat * pre)2999d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre)
3000d71ae5a4SJacob Faibussowitsch {
300137a82bf0SJed Brown   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
300237a82bf0SJed Brown 
300337a82bf0SJed Brown   PetscFunctionBegin;
30046056e507SPierre Jolivet   if (ptype) *ptype = jac->schurpre;
30056056e507SPierre Jolivet   if (pre) *pre = jac->schur_user;
30063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
300737a82bf0SJed Brown }
300837a82bf0SJed Brown 
3009ab1df9f5SJed Brown /*@
30101d27aa22SBarry Smith   PCFieldSplitSetSchurFactType -  sets which blocks of the approximate block factorization to retain in the preconditioner {cite}`murphy2000note` and {cite}`ipsen2001note`
3011ab1df9f5SJed Brown 
3012c3339decSBarry Smith   Collective
3013ab1df9f5SJed Brown 
3014ab1df9f5SJed Brown   Input Parameters:
3015ab1df9f5SJed Brown + pc    - the preconditioner context
3016f1580f4eSBarry Smith - ftype - which blocks of factorization to retain, `PC_FIELDSPLIT_SCHUR_FACT_FULL` is default
3017ab1df9f5SJed Brown 
3018f1580f4eSBarry Smith   Options Database Key:
3019d59693daSPierre Jolivet . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - default is `full`
3020ab1df9f5SJed Brown 
3021ab1df9f5SJed Brown   Level: intermediate
3022ab1df9f5SJed Brown 
3023ab1df9f5SJed Brown   Notes:
3024366f9a6aSPierre Jolivet   The `full` factorization is
3025ab1df9f5SJed Brown 
3026a077d33dSBarry Smith   ```{math}
3027a077d33dSBarry Smith   \left(\begin{array}{cc} A & B \\
3028a077d33dSBarry Smith   C & E \\
3029a077d33dSBarry Smith   \end{array}\right) =
3030366f9a6aSPierre Jolivet   \left(\begin{array}{cc} I & 0 \\
3031366f9a6aSPierre Jolivet   C A^{-1} & I \\
3032a077d33dSBarry Smith   \end{array}\right)
3033a077d33dSBarry Smith   \left(\begin{array}{cc} A & 0 \\
3034a077d33dSBarry Smith   0 & S \\
3035a077d33dSBarry Smith   \end{array}\right)
3036a077d33dSBarry Smith   \left(\begin{array}{cc} I & A^{-1}B \\
3037a077d33dSBarry Smith   0 & I \\
3038366f9a6aSPierre Jolivet   \end{array}\right) = L D U,
3039a077d33dSBarry Smith   ```
3040a077d33dSBarry Smith 
3041366f9a6aSPierre Jolivet   where $ S = E - C A^{-1} B $. In practice, the full factorization is applied via block triangular solves with the grouping $L(DU)$. `upper` uses $DU$, `lower` uses $LD$,
3042366f9a6aSPierre Jolivet   and `diag` is the diagonal part with the sign of $S$ flipped (because this makes the preconditioner positive definite for many formulations,
3043a077d33dSBarry Smith   thus allowing the use of `KSPMINRES)`. Sign flipping of $S$ can be turned off with `PCFieldSplitSetSchurScale()`.
3044a077d33dSBarry Smith 
3045a077d33dSBarry Smith   If $A$ and $S$ are solved exactly
3046366f9a6aSPierre Jolivet +  1 - `full` factorization is a direct solver.
3047366f9a6aSPierre Jolivet .  2 - The preconditioned operator with `lower` or `upper` has all eigenvalues equal to 1 and minimal polynomial of degree 2, so `KSPGMRES` converges in 2 iterations.
3048366f9a6aSPierre Jolivet -  3 - With `diag`, the preconditioned operator has three distinct nonzero eigenvalues and minimal polynomial of degree at most 4, so `KSPGMRES` converges in at most 4 iterations.
3049ab1df9f5SJed Brown 
3050f1580f4eSBarry Smith   If the iteration count is very low, consider using `KSPFGMRES` or `KSPGCR` which can use one less preconditioner
30510ffb0e17SBarry Smith   application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice.
30520ffb0e17SBarry Smith 
3053366f9a6aSPierre Jolivet   For symmetric problems in which $A$ is positive definite and $S$ is negative definite, `diag` can be used with `KSPMINRES`.
30540ffb0e17SBarry Smith 
3055366f9a6aSPierre Jolivet   A flexible method like `KSPFGMRES` or `KSPGCR`, [](sec_flexibleksp), must be used if the fieldsplit preconditioner is nonlinear (e.g., a few iterations of a Krylov method is used to solve with $A$ or $S$).
3056ab1df9f5SJed Brown 
30571d27aa22SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurScale()`,
3058a077d33dSBarry Smith           [](sec_flexibleksp), `PCFieldSplitSetSchurPre()`
3059ab1df9f5SJed Brown @*/
PCFieldSplitSetSchurFactType(PC pc,PCFieldSplitSchurFactType ftype)3060d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurFactType(PC pc, PCFieldSplitSchurFactType ftype)
3061d71ae5a4SJacob Faibussowitsch {
3062ab1df9f5SJed Brown   PetscFunctionBegin;
3063ab1df9f5SJed Brown   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3064cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurFactType_C", (PC, PCFieldSplitSchurFactType), (pc, ftype));
30653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3066ab1df9f5SJed Brown }
3067ab1df9f5SJed Brown 
PCFieldSplitSetSchurFactType_FieldSplit(PC pc,PCFieldSplitSchurFactType ftype)3068d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc, PCFieldSplitSchurFactType ftype)
3069d71ae5a4SJacob Faibussowitsch {
3070ab1df9f5SJed Brown   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3071ab1df9f5SJed Brown 
3072ab1df9f5SJed Brown   PetscFunctionBegin;
3073ab1df9f5SJed Brown   jac->schurfactorization = ftype;
30743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3075ab1df9f5SJed Brown }
3076ab1df9f5SJed Brown 
3077c096484dSStefano Zampini /*@
3078f1580f4eSBarry Smith   PCFieldSplitSetSchurScale -  Controls the sign flip of S for `PC_FIELDSPLIT_SCHUR_FACT_DIAG`.
3079c096484dSStefano Zampini 
3080c3339decSBarry Smith   Collective
3081c096484dSStefano Zampini 
3082c096484dSStefano Zampini   Input Parameters:
3083c096484dSStefano Zampini + pc    - the preconditioner context
3084c096484dSStefano Zampini - scale - scaling factor for the Schur complement
3085c096484dSStefano Zampini 
3086f1580f4eSBarry Smith   Options Database Key:
30871d27aa22SBarry Smith . -pc_fieldsplit_schur_scale <scale> - default is -1.0
3088c096484dSStefano Zampini 
3089c096484dSStefano Zampini   Level: intermediate
3090c096484dSStefano Zampini 
309142747ad1SJacob Faibussowitsch .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurFactType`, `PCFieldSplitSetSchurFactType()`
3092c096484dSStefano Zampini @*/
PCFieldSplitSetSchurScale(PC pc,PetscScalar scale)3093d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurScale(PC pc, PetscScalar scale)
3094d71ae5a4SJacob Faibussowitsch {
3095c096484dSStefano Zampini   PetscFunctionBegin;
3096c096484dSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3097c096484dSStefano Zampini   PetscValidLogicalCollectiveScalar(pc, scale, 2);
3098cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurScale_C", (PC, PetscScalar), (pc, scale));
30993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3100c096484dSStefano Zampini }
3101c096484dSStefano Zampini 
PCFieldSplitSetSchurScale_FieldSplit(PC pc,PetscScalar scale)3102d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc, PetscScalar scale)
3103d71ae5a4SJacob Faibussowitsch {
3104c096484dSStefano Zampini   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3105c096484dSStefano Zampini 
3106c096484dSStefano Zampini   PetscFunctionBegin;
3107c096484dSStefano Zampini   jac->schurscale = scale;
31083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3109c096484dSStefano Zampini }
3110c096484dSStefano Zampini 
311130ad9308SMatthew Knepley /*@C
31128c03b21aSDmitry Karpeev   PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
311330ad9308SMatthew Knepley 
3114c3339decSBarry Smith   Collective
311530ad9308SMatthew Knepley 
311630ad9308SMatthew Knepley   Input Parameter:
311730ad9308SMatthew Knepley . pc - the preconditioner context
311830ad9308SMatthew Knepley 
311930ad9308SMatthew Knepley   Output Parameters:
3120a04f6461SBarry Smith + A00 - the (0,0) block
3121a04f6461SBarry Smith . A01 - the (0,1) block
3122a04f6461SBarry Smith . A10 - the (1,0) block
3123a04f6461SBarry Smith - A11 - the (1,1) block
312430ad9308SMatthew Knepley 
312530ad9308SMatthew Knepley   Level: advanced
312630ad9308SMatthew Knepley 
31275d83a8b1SBarry Smith   Note:
31285d83a8b1SBarry Smith   Use `NULL` for any unneeded output arguments
31295d83a8b1SBarry Smith 
313060f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `MatSchurComplementGetSubMatrices()`, `MatSchurComplementSetSubMatrices()`
313130ad9308SMatthew Knepley @*/
PCFieldSplitGetSchurBlocks(PC pc,Mat * A00,Mat * A01,Mat * A10,Mat * A11)3132d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc, Mat *A00, Mat *A01, Mat *A10, Mat *A11)
3133d71ae5a4SJacob Faibussowitsch {
313430ad9308SMatthew Knepley   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
313530ad9308SMatthew Knepley 
313630ad9308SMatthew Knepley   PetscFunctionBegin;
31370700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
313808401ef6SPierre Jolivet   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
3139a04f6461SBarry Smith   if (A00) *A00 = jac->pmat[0];
3140a04f6461SBarry Smith   if (A01) *A01 = jac->B;
3141a04f6461SBarry Smith   if (A10) *A10 = jac->C;
3142a04f6461SBarry Smith   if (A11) *A11 = jac->pmat[1];
31433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
314430ad9308SMatthew Knepley }
314530ad9308SMatthew Knepley 
3146b09e027eSCarola Kruse /*@
31471d27aa22SBarry Smith   PCFieldSplitSetGKBTol -  Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3148b09e027eSCarola Kruse 
3149c3339decSBarry Smith   Collective
3150e071a0a4SCarola Kruse 
3151b09e027eSCarola Kruse   Input Parameters:
3152b09e027eSCarola Kruse + pc        - the preconditioner context
3153b09e027eSCarola Kruse - tolerance - the solver tolerance
3154b09e027eSCarola Kruse 
3155f1580f4eSBarry Smith   Options Database Key:
31561d27aa22SBarry Smith . -pc_fieldsplit_gkb_tol <tolerance> - default is 1e-5
3157b09e027eSCarola Kruse 
3158b09e027eSCarola Kruse   Level: intermediate
3159b09e027eSCarola Kruse 
3160f1580f4eSBarry Smith   Note:
31611d27aa22SBarry Smith   The generalized GKB algorithm {cite}`arioli2013` uses a lower bound estimate of the error in energy norm as stopping criterion.
3162f1580f4eSBarry Smith   It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than
31631d27aa22SBarry Smith   this estimate, the stopping criterion is satisfactory in practical cases.
3164f1580f4eSBarry Smith 
316560f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBMaxit()`
3166b09e027eSCarola Kruse @*/
PCFieldSplitSetGKBTol(PC pc,PetscReal tolerance)3167d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBTol(PC pc, PetscReal tolerance)
3168d71ae5a4SJacob Faibussowitsch {
3169b09e027eSCarola Kruse   PetscFunctionBegin;
3170b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3171de482cd7SCarola Kruse   PetscValidLogicalCollectiveReal(pc, tolerance, 2);
3172cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBTol_C", (PC, PetscReal), (pc, tolerance));
31733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3174b09e027eSCarola Kruse }
3175b09e027eSCarola Kruse 
PCFieldSplitSetGKBTol_FieldSplit(PC pc,PetscReal tolerance)3176d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc, PetscReal tolerance)
3177d71ae5a4SJacob Faibussowitsch {
3178b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3179b09e027eSCarola Kruse 
3180b09e027eSCarola Kruse   PetscFunctionBegin;
3181b09e027eSCarola Kruse   jac->gkbtol = tolerance;
31823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3183b09e027eSCarola Kruse }
3184b09e027eSCarola Kruse 
3185b09e027eSCarola Kruse /*@
318680670ca5SBarry Smith   PCFieldSplitSetGKBMaxit -  Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3187b09e027eSCarola Kruse 
3188c3339decSBarry Smith   Collective
3189b09e027eSCarola Kruse 
3190b09e027eSCarola Kruse   Input Parameters:
3191b09e027eSCarola Kruse + pc    - the preconditioner context
3192b09e027eSCarola Kruse - maxit - the maximum number of iterations
3193b09e027eSCarola Kruse 
3194f1580f4eSBarry Smith   Options Database Key:
31951d27aa22SBarry Smith . -pc_fieldsplit_gkb_maxit <maxit> - default is 100
3196b09e027eSCarola Kruse 
3197b09e027eSCarola Kruse   Level: intermediate
3198b09e027eSCarola Kruse 
319960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBNu()`
3200b09e027eSCarola Kruse @*/
PCFieldSplitSetGKBMaxit(PC pc,PetscInt maxit)3201d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc, PetscInt maxit)
3202d71ae5a4SJacob Faibussowitsch {
3203b09e027eSCarola Kruse   PetscFunctionBegin;
3204b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3205de482cd7SCarola Kruse   PetscValidLogicalCollectiveInt(pc, maxit, 2);
3206cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBMaxit_C", (PC, PetscInt), (pc, maxit));
32073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3208b09e027eSCarola Kruse }
3209b09e027eSCarola Kruse 
PCFieldSplitSetGKBMaxit_FieldSplit(PC pc,PetscInt maxit)3210d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc, PetscInt maxit)
3211d71ae5a4SJacob Faibussowitsch {
3212b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3213b09e027eSCarola Kruse 
3214b09e027eSCarola Kruse   PetscFunctionBegin;
3215b09e027eSCarola Kruse   jac->gkbmaxit = maxit;
32163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3217b09e027eSCarola Kruse }
3218b09e027eSCarola Kruse 
3219b09e027eSCarola Kruse /*@
32201d27aa22SBarry Smith   PCFieldSplitSetGKBDelay -  Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization {cite}`arioli2013` in `PCFIELDSPLIT`
3221e071a0a4SCarola Kruse   preconditioner.
3222b09e027eSCarola Kruse 
3223c3339decSBarry Smith   Collective
3224b09e027eSCarola Kruse 
3225b09e027eSCarola Kruse   Input Parameters:
3226b09e027eSCarola Kruse + pc    - the preconditioner context
3227b09e027eSCarola Kruse - delay - the delay window in the lower bound estimate
3228b09e027eSCarola Kruse 
3229f1580f4eSBarry Smith   Options Database Key:
32301d27aa22SBarry Smith . -pc_fieldsplit_gkb_delay <delay> - default is 5
3231b09e027eSCarola Kruse 
3232b09e027eSCarola Kruse   Level: intermediate
3233b09e027eSCarola Kruse 
32341d27aa22SBarry Smith   Notes:
32351d27aa22SBarry Smith   The algorithm uses a lower bound estimate of the error in energy norm as stopping criterion. The lower bound of the error $ ||u-u^k||_H $
32361d27aa22SBarry Smith   is expressed as a truncated sum. The error at iteration k can only be measured at iteration (k + `delay`), and thus the algorithm needs
32371d27aa22SBarry Smith   at least (`delay` + 1) iterations to stop.
3238f1580f4eSBarry Smith 
32391d27aa22SBarry Smith   For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to {cite}`arioli2013`
3240f1580f4eSBarry Smith 
324160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
3242b09e027eSCarola Kruse @*/
PCFieldSplitSetGKBDelay(PC pc,PetscInt delay)3243d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBDelay(PC pc, PetscInt delay)
3244d71ae5a4SJacob Faibussowitsch {
3245b09e027eSCarola Kruse   PetscFunctionBegin;
3246b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3247b09e027eSCarola Kruse   PetscValidLogicalCollectiveInt(pc, delay, 2);
3248cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBDelay_C", (PC, PetscInt), (pc, delay));
32493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3250b09e027eSCarola Kruse }
3251b09e027eSCarola Kruse 
PCFieldSplitSetGKBDelay_FieldSplit(PC pc,PetscInt delay)3252d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc, PetscInt delay)
3253d71ae5a4SJacob Faibussowitsch {
3254b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3255b09e027eSCarola Kruse 
3256b09e027eSCarola Kruse   PetscFunctionBegin;
3257b09e027eSCarola Kruse   jac->gkbdelay = delay;
32583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3259b09e027eSCarola Kruse }
3260b09e027eSCarola Kruse 
3261b09e027eSCarola Kruse /*@
32621d27aa22SBarry Smith   PCFieldSplitSetGKBNu -  Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the
32631d27aa22SBarry Smith   Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3264b09e027eSCarola Kruse 
3265c3339decSBarry Smith   Collective
3266f1580f4eSBarry Smith 
3267f1580f4eSBarry Smith   Input Parameters:
3268f1580f4eSBarry Smith + pc - the preconditioner context
3269f1580f4eSBarry Smith - nu - the shift parameter
3270f1580f4eSBarry Smith 
327120f4b53cSBarry Smith   Options Database Key:
32721d27aa22SBarry Smith . -pc_fieldsplit_gkb_nu <nu> - default is 1
3273f1580f4eSBarry Smith 
3274f1580f4eSBarry Smith   Level: intermediate
3275b09e027eSCarola Kruse 
3276b09e027eSCarola Kruse   Notes:
32771d27aa22SBarry Smith   This shift is in general done to obtain better convergence properties for the outer loop of the algorithm. This is often achieved by choosing `nu` sufficiently large. However,
32781d27aa22SBarry Smith   if `nu` is chosen too large, the matrix H might be badly conditioned and the solution of the linear system $Hx = b$ in the inner loop becomes difficult. It is therefore
3279b09e027eSCarola Kruse   necessary to find a good balance in between the convergence of the inner and outer loop.
3280b09e027eSCarola Kruse 
32811d27aa22SBarry Smith   For `nu` = 0, no shift is done. In this case A00 has to be positive definite. The matrix N in {cite}`arioli2013` is then chosen as identity.
3282b09e027eSCarola Kruse 
328360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
3284b09e027eSCarola Kruse @*/
PCFieldSplitSetGKBNu(PC pc,PetscReal nu)3285d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBNu(PC pc, PetscReal nu)
3286d71ae5a4SJacob Faibussowitsch {
3287b09e027eSCarola Kruse   PetscFunctionBegin;
3288b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3289de482cd7SCarola Kruse   PetscValidLogicalCollectiveReal(pc, nu, 2);
3290cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBNu_C", (PC, PetscReal), (pc, nu));
32913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3292b09e027eSCarola Kruse }
3293b09e027eSCarola Kruse 
PCFieldSplitSetGKBNu_FieldSplit(PC pc,PetscReal nu)3294d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc, PetscReal nu)
3295d71ae5a4SJacob Faibussowitsch {
3296b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3297b09e027eSCarola Kruse 
3298b09e027eSCarola Kruse   PetscFunctionBegin;
3299b09e027eSCarola Kruse   jac->gkbnu = nu;
33003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3301b09e027eSCarola Kruse }
3302b09e027eSCarola Kruse 
PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)3303d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc, PCCompositeType type)
3304d71ae5a4SJacob Faibussowitsch {
330579416396SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
330679416396SBarry Smith 
330779416396SBarry Smith   PetscFunctionBegin;
330879416396SBarry Smith   jac->type = type;
33092e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
33102e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
33112e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
33122e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
33132e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
33142e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
33152e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
33162e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
33172e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
3318e071a0a4SCarola Kruse 
33193b224e63SBarry Smith   if (type == PC_COMPOSITE_SCHUR) {
33203b224e63SBarry Smith     pc->ops->apply          = PCApply_FieldSplit_Schur;
33217b665727SPierre Jolivet     pc->ops->applytranspose = PCApplyTranspose_FieldSplit_Schur;
3322f5b94327SPierre Jolivet     pc->ops->matapply       = PCMatApply_FieldSplit_Schur;
33233b224e63SBarry Smith     pc->ops->view           = PCView_FieldSplit_Schur;
332473716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit_Schur;
33252fa5cd67SKarl Rupp 
33269566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit_Schur));
33279566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", PCFieldSplitSetSchurPre_FieldSplit));
33289566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", PCFieldSplitGetSchurPre_FieldSplit));
33299566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", PCFieldSplitSetSchurFactType_FieldSplit));
33309566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", PCFieldSplitSetSchurScale_FieldSplit));
3331a51937d4SCarola Kruse   } else if (type == PC_COMPOSITE_GKB) {
3332a51937d4SCarola Kruse     pc->ops->apply          = PCApply_FieldSplit_GKB;
33337ff38633SStefano Zampini     pc->ops->applytranspose = NULL;
3334d484b384SBoris Martin     pc->ops->matapply       = NULL;
3335a51937d4SCarola Kruse     pc->ops->view           = PCView_FieldSplit_GKB;
333673716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit_GKB;
3337e69d4d44SBarry Smith 
33389566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
33399566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", PCFieldSplitSetGKBTol_FieldSplit));
33409566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", PCFieldSplitSetGKBMaxit_FieldSplit));
33419566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", PCFieldSplitSetGKBNu_FieldSplit));
33429566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", PCFieldSplitSetGKBDelay_FieldSplit));
33433b224e63SBarry Smith   } else {
33443b224e63SBarry Smith     pc->ops->apply          = PCApply_FieldSplit;
33457ff38633SStefano Zampini     pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
3346d484b384SBoris Martin     pc->ops->matapply       = PCMatApply_FieldSplit;
33473b224e63SBarry Smith     pc->ops->view           = PCView_FieldSplit;
334873716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit;
33492fa5cd67SKarl Rupp 
33509566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
33513b224e63SBarry Smith   }
33523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
335379416396SBarry Smith }
335479416396SBarry Smith 
PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)3355d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc, PetscInt bs)
3356d71ae5a4SJacob Faibussowitsch {
335751f519a2SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
335851f519a2SBarry Smith 
335951f519a2SBarry Smith   PetscFunctionBegin;
336063a3b9bcSJacob Faibussowitsch   PetscCheck(bs >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs);
33612472a847SBarry Smith   PetscCheck(jac->bs <= 0 || jac->bs == bs, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Cannot change fieldsplit blocksize from %" PetscInt_FMT " to %" PetscInt_FMT " after it has been set", jac->bs, bs);
336251f519a2SBarry Smith   jac->bs = bs;
33633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
336451f519a2SBarry Smith }
336551f519a2SBarry Smith 
PCSetCoordinates_FieldSplit(PC pc,PetscInt dim,PetscInt nloc,PetscReal coords[])3366d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[])
3367d71ae5a4SJacob Faibussowitsch {
33685ddf11f8SNicolas Barnafi   PC_FieldSplit    *jac           = (PC_FieldSplit *)pc->data;
33695ddf11f8SNicolas Barnafi   PC_FieldSplitLink ilink_current = jac->head;
33705ddf11f8SNicolas Barnafi   IS                is_owned;
33715ddf11f8SNicolas Barnafi 
33725ddf11f8SNicolas Barnafi   PetscFunctionBegin;
33735ddf11f8SNicolas Barnafi   jac->coordinates_set = PETSC_TRUE; // Internal flag
3374f3fa974cSJacob Faibussowitsch   PetscCall(MatGetOwnershipIS(pc->mat, &is_owned, NULL));
33755ddf11f8SNicolas Barnafi 
33765ddf11f8SNicolas Barnafi   while (ilink_current) {
33775ddf11f8SNicolas Barnafi     // For each IS, embed it to get local coords indces
33785ddf11f8SNicolas Barnafi     IS              is_coords;
33795ddf11f8SNicolas Barnafi     PetscInt        ndofs_block;
33805ddf11f8SNicolas Barnafi     const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block
33815ddf11f8SNicolas Barnafi 
33825ddf11f8SNicolas Barnafi     // Setting drop to true for safety. It should make no difference.
33839566063dSJacob Faibussowitsch     PetscCall(ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords));
33849566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is_coords, &ndofs_block));
33859566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is_coords, &block_dofs_enumeration));
33865ddf11f8SNicolas Barnafi 
33875ddf11f8SNicolas Barnafi     // Allocate coordinates vector and set it directly
3388f4f49eeaSPierre Jolivet     PetscCall(PetscMalloc1(ndofs_block * dim, &ilink_current->coords));
33895ddf11f8SNicolas Barnafi     for (PetscInt dof = 0; dof < ndofs_block; ++dof) {
3390ad540459SPierre Jolivet       for (PetscInt d = 0; d < dim; ++d) (ilink_current->coords)[dim * dof + d] = coords[dim * block_dofs_enumeration[dof] + d];
33915ddf11f8SNicolas Barnafi     }
33925ddf11f8SNicolas Barnafi     ilink_current->dim   = dim;
33935ddf11f8SNicolas Barnafi     ilink_current->ndofs = ndofs_block;
33949566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is_coords, &block_dofs_enumeration));
33959566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_coords));
33965ddf11f8SNicolas Barnafi     ilink_current = ilink_current->next;
33975ddf11f8SNicolas Barnafi   }
33989566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_owned));
33993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34005ddf11f8SNicolas Barnafi }
34015ddf11f8SNicolas Barnafi 
3402bc08b0f1SBarry Smith /*@
3403f1580f4eSBarry Smith   PCFieldSplitSetType - Sets the type, `PCCompositeType`, of a `PCFIELDSPLIT`
340479416396SBarry Smith 
3405c3339decSBarry Smith   Collective
340679416396SBarry Smith 
3407d8d19677SJose E. Roman   Input Parameters:
3408a2b725a8SWilliam Gropp + pc   - the preconditioner context
3409a077d33dSBarry Smith - type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`,
3410a077d33dSBarry Smith          `PC_COMPOSITE_GKB`
341179416396SBarry Smith 
341279416396SBarry Smith   Options Database Key:
34131d27aa22SBarry Smith . -pc_fieldsplit_type <one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
341479416396SBarry Smith 
3415feefa0e1SJacob Faibussowitsch   Level: intermediate
341679416396SBarry Smith 
341760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCCompositeType`, `PCCompositeGetType()`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`,
3418a077d33dSBarry Smith           `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`, `PCFieldSplitSetSchurFactType()`
341979416396SBarry Smith @*/
PCFieldSplitSetType(PC pc,PCCompositeType type)3420d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetType(PC pc, PCCompositeType type)
3421d71ae5a4SJacob Faibussowitsch {
342279416396SBarry Smith   PetscFunctionBegin;
34230700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3424cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetType_C", (PC, PCCompositeType), (pc, type));
34253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
342679416396SBarry Smith }
342779416396SBarry Smith 
3428b02e2d75SMatthew G Knepley /*@
3429f1580f4eSBarry Smith   PCFieldSplitGetType - Gets the type, `PCCompositeType`, of a `PCFIELDSPLIT`
3430b02e2d75SMatthew G Knepley 
3431b02e2d75SMatthew G Knepley   Not collective
3432b02e2d75SMatthew G Knepley 
3433b02e2d75SMatthew G Knepley   Input Parameter:
3434b02e2d75SMatthew G Knepley . pc - the preconditioner context
3435b02e2d75SMatthew G Knepley 
3436b02e2d75SMatthew G Knepley   Output Parameter:
3437f1580f4eSBarry Smith . type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`
3438b02e2d75SMatthew G Knepley 
3439feefa0e1SJacob Faibussowitsch   Level: intermediate
3440b02e2d75SMatthew G Knepley 
344160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCompositeSetType()`, `PCFIELDSPLIT`, `PCCompositeType`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`,
3442f1580f4eSBarry Smith           `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`
3443b02e2d75SMatthew G Knepley @*/
PCFieldSplitGetType(PC pc,PCCompositeType * type)3444d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type)
3445d71ae5a4SJacob Faibussowitsch {
3446b02e2d75SMatthew G Knepley   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3447b02e2d75SMatthew G Knepley 
3448b02e2d75SMatthew G Knepley   PetscFunctionBegin;
3449b02e2d75SMatthew G Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
34504f572ea9SToby Isaac   PetscAssertPointer(type, 2);
3451b02e2d75SMatthew G Knepley   *type = jac->type;
34523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3453b02e2d75SMatthew G Knepley }
3454b02e2d75SMatthew G Knepley 
34554ab8060aSDmitry Karpeev /*@
3456f1580f4eSBarry Smith   PCFieldSplitSetDMSplits - Flags whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible.
34574ab8060aSDmitry Karpeev 
3458c3339decSBarry Smith   Logically Collective
34594ab8060aSDmitry Karpeev 
34604ab8060aSDmitry Karpeev   Input Parameters:
34614ab8060aSDmitry Karpeev + pc  - the preconditioner context
3462f1580f4eSBarry Smith - flg - boolean indicating whether to use field splits defined by the `DM`
34634ab8060aSDmitry Karpeev 
34644ab8060aSDmitry Karpeev   Options Database Key:
3465f1580f4eSBarry Smith . -pc_fieldsplit_dm_splits <bool> - use the field splits defined by the `DM`
34664ab8060aSDmitry Karpeev 
3467feefa0e1SJacob Faibussowitsch   Level: intermediate
34684ab8060aSDmitry Karpeev 
346973ff1848SBarry Smith   Developer Note:
347073ff1848SBarry Smith   The name should be `PCFieldSplitSetUseDMSplits()`, similar change to options database
347173ff1848SBarry Smith 
3472f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
34734ab8060aSDmitry Karpeev @*/
PCFieldSplitSetDMSplits(PC pc,PetscBool flg)3474d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDMSplits(PC pc, PetscBool flg)
3475d71ae5a4SJacob Faibussowitsch {
34764ab8060aSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
34774ab8060aSDmitry Karpeev   PetscBool      isfs;
34784ab8060aSDmitry Karpeev 
34794ab8060aSDmitry Karpeev   PetscFunctionBegin;
34804ab8060aSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
34814ab8060aSDmitry Karpeev   PetscValidLogicalCollectiveBool(pc, flg, 2);
34829566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
3483ad540459SPierre Jolivet   if (isfs) jac->dm_splits = flg;
34843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34854ab8060aSDmitry Karpeev }
34864ab8060aSDmitry Karpeev 
34874ab8060aSDmitry Karpeev /*@
3488f1580f4eSBarry Smith   PCFieldSplitGetDMSplits - Returns flag indicating whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible.
34894ab8060aSDmitry Karpeev 
34904ab8060aSDmitry Karpeev   Logically Collective
34914ab8060aSDmitry Karpeev 
34924ab8060aSDmitry Karpeev   Input Parameter:
34934ab8060aSDmitry Karpeev . pc - the preconditioner context
34944ab8060aSDmitry Karpeev 
34954ab8060aSDmitry Karpeev   Output Parameter:
3496f1580f4eSBarry Smith . flg - boolean indicating whether to use field splits defined by the `DM`
34974ab8060aSDmitry Karpeev 
3498feefa0e1SJacob Faibussowitsch   Level: intermediate
34994ab8060aSDmitry Karpeev 
350073ff1848SBarry Smith   Developer Note:
350173ff1848SBarry Smith   The name should be `PCFieldSplitGetUseDMSplits()`
350273ff1848SBarry Smith 
3503f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
35044ab8060aSDmitry Karpeev @*/
PCFieldSplitGetDMSplits(PC pc,PetscBool * flg)3505d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDMSplits(PC pc, PetscBool *flg)
3506d71ae5a4SJacob Faibussowitsch {
35074ab8060aSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35084ab8060aSDmitry Karpeev   PetscBool      isfs;
35094ab8060aSDmitry Karpeev 
35104ab8060aSDmitry Karpeev   PetscFunctionBegin;
35114ab8060aSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
35124f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
35139566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
35144ab8060aSDmitry Karpeev   if (isfs) {
35154ab8060aSDmitry Karpeev     if (flg) *flg = jac->dm_splits;
35164ab8060aSDmitry Karpeev   }
35173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35184ab8060aSDmitry Karpeev }
35194ab8060aSDmitry Karpeev 
35207b752e3dSPatrick Sanan /*@
3521f1580f4eSBarry Smith   PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries.
35227b752e3dSPatrick Sanan 
35237b752e3dSPatrick Sanan   Logically Collective
35247b752e3dSPatrick Sanan 
35257b752e3dSPatrick Sanan   Input Parameter:
35267b752e3dSPatrick Sanan . pc - the preconditioner context
35277b752e3dSPatrick Sanan 
35287b752e3dSPatrick Sanan   Output Parameter:
35297b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not
35307b752e3dSPatrick Sanan 
3531feefa0e1SJacob Faibussowitsch   Level: intermediate
35327b752e3dSPatrick Sanan 
353360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()`
35347b752e3dSPatrick Sanan @*/
PCFieldSplitGetDetectSaddlePoint(PC pc,PetscBool * flg)3535d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc, PetscBool *flg)
3536d71ae5a4SJacob Faibussowitsch {
35377b752e3dSPatrick Sanan   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35387b752e3dSPatrick Sanan 
35397b752e3dSPatrick Sanan   PetscFunctionBegin;
35407b752e3dSPatrick Sanan   *flg = jac->detect;
35413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35427b752e3dSPatrick Sanan }
35437b752e3dSPatrick Sanan 
35447b752e3dSPatrick Sanan /*@
3545f1580f4eSBarry Smith   PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries.
35467b752e3dSPatrick Sanan 
35477b752e3dSPatrick Sanan   Logically Collective
35487b752e3dSPatrick Sanan 
35497b752e3dSPatrick Sanan   Input Parameter:
35507b752e3dSPatrick Sanan . pc - the preconditioner context
35517b752e3dSPatrick Sanan 
35527b752e3dSPatrick Sanan   Output Parameter:
35537b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not
35547b752e3dSPatrick Sanan 
35557b752e3dSPatrick Sanan   Options Database Key:
3556147403d9SBarry Smith . -pc_fieldsplit_detect_saddle_point <bool> - detect and use the saddle point
3557147403d9SBarry Smith 
3558feefa0e1SJacob Faibussowitsch   Level: intermediate
355960f59c3bSBarry Smith 
3560f1580f4eSBarry Smith   Note:
3561f1580f4eSBarry Smith   Also sets the split type to `PC_COMPOSITE_SCHUR` (see `PCFieldSplitSetType()`) and the Schur preconditioner type to `PC_FIELDSPLIT_SCHUR_PRE_SELF` (see `PCFieldSplitSetSchurPre()`).
35627b752e3dSPatrick Sanan 
356360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDetectSaddlePoint()`, `PCFieldSplitSetType()`, `PCFieldSplitSetSchurPre()`, `PC_FIELDSPLIT_SCHUR_PRE_SELF`
35647b752e3dSPatrick Sanan @*/
PCFieldSplitSetDetectSaddlePoint(PC pc,PetscBool flg)3565d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc, PetscBool flg)
3566d71ae5a4SJacob Faibussowitsch {
35677b752e3dSPatrick Sanan   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35687b752e3dSPatrick Sanan 
35697b752e3dSPatrick Sanan   PetscFunctionBegin;
35707b752e3dSPatrick Sanan   jac->detect = flg;
35717b752e3dSPatrick Sanan   if (jac->detect) {
35729566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR));
35739566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL));
35747b752e3dSPatrick Sanan   }
35753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35767b752e3dSPatrick Sanan }
35777b752e3dSPatrick Sanan 
35780971522cSBarry Smith /*MC
3579a8c7a070SBarry Smith   PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
35800b4b7b1cSBarry Smith   collections of variables (that may overlap) called fields or splits. Each field often represents a different continuum variable
35810b4b7b1cSBarry Smith   represented on a grid, such as velocity, pressure, or temperature.
35820b4b7b1cSBarry Smith   In the literature these are sometimes called block preconditioners; but should not be confused with `PCBJACOBI`.
35830b4b7b1cSBarry Smith   See [the users manual section on "Solving Block Matrices"](sec_block_matrices) for more details.
35840971522cSBarry Smith 
358579416396SBarry Smith   Options Database Keys:
3586de37d9f1SPatrick Sanan +   -pc_fieldsplit_%d_fields <a,b,..>                                                - indicates the fields to be used in the `%d`'th split
358781540f2fSBarry Smith .   -pc_fieldsplit_default                                                           - automatically add any fields to additional splits that have not
3588de37d9f1SPatrick Sanan                                                                                        been supplied explicitly by `-pc_fieldsplit_%d_fields`
358981540f2fSBarry Smith .   -pc_fieldsplit_block_size <bs>                                                   - size of block that defines fields (i.e. there are bs fields)
359080670ca5SBarry Smith                                                                                        when the matrix is not of `MatType` `MATNEST`
3591a51937d4SCarola Kruse .   -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting
3592d59693daSPierre Jolivet .   -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full>                     - default is `a11`; see `PCFieldSplitSetSchurPre()`
35931d27aa22SBarry Smith .   -pc_fieldsplit_schur_fact_type <diag,lower,upper,full>                           - set factorization type when using `-pc_fieldsplit_type schur`;
35941d27aa22SBarry Smith                                                                                        see `PCFieldSplitSetSchurFactType()`
359573ff1848SBarry Smith .   -pc_fieldsplit_dm_splits <true,false> (default is true)                          - Whether to use `DMCreateFieldDecomposition()` for splits
3596fb6809a2SPatrick Sanan -   -pc_fieldsplit_detect_saddle_point                                               - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver
359779416396SBarry Smith 
3598de37d9f1SPatrick Sanan   Options prefixes for inner solvers when using the Schur complement preconditioner are `-fieldsplit_0_` and `-fieldsplit_1_` .
3599de37d9f1SPatrick Sanan   The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is `-fieldsplit_0_`
360060f59c3bSBarry Smith   For all other solvers they are `-fieldsplit_%d_` for the `%d`'th field; use `-fieldsplit_` for all fields.
360160f59c3bSBarry Smith 
360222399129SNuno Nobre   To set options on the solvers for all blocks, prepend `-fieldsplit_` to all the `PC`
360322399129SNuno Nobre   options database keys. For example, `-fieldsplit_pc_type ilu` `-fieldsplit_pc_factor_levels 1`.
360460f59c3bSBarry Smith 
360560f59c3bSBarry Smith   To set the options on the solvers separate for each block call `PCFieldSplitGetSubKSP()`
360660f59c3bSBarry Smith   and set the options directly on the resulting `KSP` object
360760f59c3bSBarry Smith 
360860f59c3bSBarry Smith   Level: intermediate
36095d4c12cdSJungho Lee 
3610c8a0d604SMatthew G Knepley   Notes:
361180670ca5SBarry Smith   Use `PCFieldSplitSetFields()` to set splits defined by "strided" entries or with a `MATNEST` and `PCFieldSplitSetIS()`
3612f1580f4eSBarry Smith   to define a split by an arbitrary collection of entries.
3613d32f9abdSBarry Smith 
361473ff1848SBarry Smith   If no splits are set, the default is used. If a `DM` is associated with the `PC` and it supports
361580670ca5SBarry Smith   `DMCreateFieldDecomposition()`, then that is used for the default. Otherwise if the matrix is not `MATNEST`, the splits are defined by entries strided by bs,
3616de37d9f1SPatrick Sanan   beginning at 0 then 1, etc to bs-1. The block size can be set with `PCFieldSplitSetBlockSize()`,
3617d32f9abdSBarry Smith   if this is not called the block size defaults to the blocksize of the second matrix passed
3618de37d9f1SPatrick Sanan   to `KSPSetOperators()`/`PCSetOperators()`.
3619d32f9abdSBarry Smith 
3620de37d9f1SPatrick Sanan   For the Schur complement preconditioner if
3621de37d9f1SPatrick Sanan   ```{math}
3622de37d9f1SPatrick Sanan     J = \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{10} & A_{11} \end{array}\right]
3623de37d9f1SPatrick Sanan   ```
3624e69d4d44SBarry Smith 
3625de37d9f1SPatrick Sanan   the preconditioner using `full` factorization is logically
3626de37d9f1SPatrick Sanan   ```{math}
3627f820a28cSNuno Nobre     \left[\begin{array}{cc} I & -\text{ksp}(A_{00}) A_{01} \\ 0 & I \end{array}\right] \left[\begin{array}{cc} \text{ksp}(A_{00}) & 0 \\ 0 & \text{ksp}(S) \end{array}\right] \left[\begin{array}{cc} I & 0 \\ -A_{10} \text{ksp}(A_{00}) & I \end{array}\right]
3628de37d9f1SPatrick Sanan       ```
3629cee94454SNuno Nobre   where the action of $\text{ksp}(A_{00})$ is applied using the `KSP` solver with prefix `-fieldsplit_0_`.  $S$ is the Schur complement
3630de37d9f1SPatrick Sanan   ```{math}
3631223e5b4fSPatrick Sanan      S = A_{11} - A_{10} \text{ksp}(A_{00}) A_{01}
3632de37d9f1SPatrick Sanan   ```
36337cbeddf0SNuno Nobre   which is usually dense and not stored explicitly.  The action of $\text{ksp}(S)$ is computed using the `KSP` solver with prefix `-fieldsplit_splitname_` (where `splitname`
36347cbeddf0SNuno Nobre   was given in providing the SECOND split or 1 if not given). Accordingly, if using `PCFieldSplitGetSubKSP()`, the array of sub-`KSP` contexts will hold two `KSP`s: at its
36357cbeddf0SNuno Nobre   0th index, the `KSP` associated with `-fieldsplit_0_`, and at its 1st index, the `KSP` corresponding to `-fieldsplit_1_`.
3636d82b6cdfSNuno Nobre   By default, $A_{11}$ is used to construct a preconditioner for $S$, use `PCFieldSplitSetSchurPre()` for all the possible ways to construct the preconditioner for $S$.
3637de37d9f1SPatrick Sanan 
3638de37d9f1SPatrick Sanan   The factorization type is set using `-pc_fieldsplit_schur_fact_type <diag, lower, upper, full>`. `full` is shown above,
3639de37d9f1SPatrick Sanan   `diag` gives
3640de37d9f1SPatrick Sanan   ```{math}
3641f820a28cSNuno Nobre     \left[\begin{array}{cc} \text{ksp}(A_{00}) & 0 \\  0 & -\text{ksp}(S) \end{array}\right]
3642de37d9f1SPatrick Sanan   ```
3643de37d9f1SPatrick Sanan   Note that, slightly counter intuitively, there is a negative in front of the $\text{ksp}(S)$  so that the preconditioner is positive definite. For SPD matrices $J$, the sign flip
3644de37d9f1SPatrick Sanan   can be turned off with `PCFieldSplitSetSchurScale()` or by command line `-pc_fieldsplit_schur_scale 1.0`. The `lower` factorization is the inverse of
3645de37d9f1SPatrick Sanan   ```{math}
3646de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & 0 \\  A_{10} & S \end{array}\right]
3647de37d9f1SPatrick Sanan   ```
3648cee94454SNuno Nobre   where the inverses of $A_{00}$ and $S$ are applied using `KSP`s. The upper factorization is the inverse of
3649de37d9f1SPatrick Sanan   ```{math}
3650de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & A_{01} \\  0 & S \end{array}\right]
3651de37d9f1SPatrick Sanan   ```
3652de37d9f1SPatrick Sanan   where again the inverses of $A_{00}$ and $S$ are applied using `KSP`s.
3653de37d9f1SPatrick Sanan 
3654de37d9f1SPatrick Sanan   If only one set of indices (one `IS`) is provided with `PCFieldSplitSetIS()` then the complement of that `IS`
365580670ca5SBarry Smith   is used automatically for a second submatrix.
3656edf189efSBarry Smith 
3657f1580f4eSBarry Smith   The fieldsplit preconditioner cannot currently be used with the `MATBAIJ` or `MATSBAIJ` data formats if the blocksize is larger than 1.
365880670ca5SBarry Smith   Generally it should be used with the `MATAIJ` or `MATNEST` `MatType`
3659ff218e97SBarry Smith 
366080670ca5SBarry Smith   The forms of these preconditioners are closely related, if not identical, to forms derived as "Distributive Iterations", see,
36611d569b8fSBarry Smith   for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling {cite}`wesseling2009`.
366280670ca5SBarry Smith   One can also use `PCFIELDSPLIT` inside a smoother resulting in "Distributive Smoothers".
36630716a85fSBarry Smith 
3664de37d9f1SPatrick Sanan   See "A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations" {cite}`elman2008tcp`.
3665a6a584a2SBarry Smith 
3666de37d9f1SPatrick Sanan   The Constrained Pressure Preconditioner (CPR) can be implemented using `PCCOMPOSITE` with `PCGALERKIN`. CPR first solves an $R A P$ subsystem, updates the
3667de37d9f1SPatrick Sanan   residual on all variables (`PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)`), and then applies a simple ILU like preconditioner on all the variables.
3668a51937d4SCarola Kruse 
3669de37d9f1SPatrick Sanan   The generalized Golub-Kahan bidiagonalization preconditioner (GKB) can be applied to symmetric $2 \times 2$ block matrices of the shape
3670de37d9f1SPatrick Sanan   ```{math}
3671de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{01}' & 0 \end{array}\right]
3672de37d9f1SPatrick Sanan   ```
36731d569b8fSBarry Smith   with $A_{00}$ positive semi-definite. The implementation follows {cite}`arioli2013`. Therein, we choose $N := 1/\nu * I$ and the $(1,1)$-block of the matrix is modified to $H = _{A00} + \nu*A_{01}*A_{01}'$.
3674de37d9f1SPatrick Sanan   A linear system $Hx = b$ has to be solved in each iteration of the GKB algorithm. This solver is chosen with the option prefix `-fieldsplit_0_`.
3675a51937d4SCarola Kruse 
36760b4b7b1cSBarry Smith   Some `PCFIELDSPLIT` variants are called physics-based preconditioners, since the preconditioner takes into account the underlying physics of the
36770b4b7b1cSBarry Smith   problem. But this nomenclature is not well-defined.
36780b4b7b1cSBarry Smith 
367960f59c3bSBarry Smith   Developer Note:
368060f59c3bSBarry Smith   The Schur complement functionality of `PCFIELDSPLIT` should likely be factored into its own `PC` thus simplifying the implementation of the preconditioners and their
368160f59c3bSBarry Smith   user API.
3682f1580f4eSBarry Smith 
368360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCLSC`,
3684db781477SPatrick Sanan           `PCFieldSplitGetSubKSP()`, `PCFieldSplitSchurGetSubKSP()`, `PCFieldSplitSetFields()`,
3685db781477SPatrick Sanan           `PCFieldSplitSetType()`, `PCFieldSplitSetIS()`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitSetSchurFactType()`,
3686db781477SPatrick Sanan           `MatSchurComplementSetAinvType()`, `PCFieldSplitSetSchurScale()`, `PCFieldSplitSetDetectSaddlePoint()`
36870971522cSBarry Smith M*/
36880971522cSBarry Smith 
PCCreate_FieldSplit(PC pc)3689d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc)
3690d71ae5a4SJacob Faibussowitsch {
36910971522cSBarry Smith   PC_FieldSplit *jac;
36920971522cSBarry Smith 
36930971522cSBarry Smith   PetscFunctionBegin;
36944dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&jac));
36952fa5cd67SKarl Rupp 
36960971522cSBarry Smith   jac->bs                 = -1;
36973e197d65SBarry Smith   jac->type               = PC_COMPOSITE_MULTIPLICATIVE;
3698e6cab6aaSJed Brown   jac->schurpre           = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
3699c9c6ffaaSJed Brown   jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL;
3700c096484dSStefano Zampini   jac->schurscale         = -1.0;
3701fbe7908bSJed Brown   jac->dm_splits          = PETSC_TRUE;
3702a51937d4SCarola Kruse   jac->gkbtol             = 1e-5;
3703a51937d4SCarola Kruse   jac->gkbdelay           = 5;
3704a51937d4SCarola Kruse   jac->gkbnu              = 1;
3705a51937d4SCarola Kruse   jac->gkbmaxit           = 100;
370651f519a2SBarry Smith 
37070971522cSBarry Smith   pc->data = (void *)jac;
37080971522cSBarry Smith 
37090971522cSBarry Smith   pc->ops->setup           = PCSetUp_FieldSplit;
3710574deadeSBarry Smith   pc->ops->reset           = PCReset_FieldSplit;
37110971522cSBarry Smith   pc->ops->destroy         = PCDestroy_FieldSplit;
37120971522cSBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_FieldSplit;
37130a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
37140971522cSBarry Smith 
37159566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", PCFieldSplitSchurGetSubKSP_FieldSplit));
37169566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", PCFieldSplitSetFields_FieldSplit));
37179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_FieldSplit));
37189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", PCFieldSplitSetType_FieldSplit));
37199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", PCFieldSplitSetBlockSize_FieldSplit));
37209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", PCFieldSplitRestrictIS_FieldSplit));
37219566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_FieldSplit));
37227ff38633SStefano Zampini 
37237ff38633SStefano Zampini   /* Initialize function pointers */
37247ff38633SStefano Zampini   PetscCall(PCFieldSplitSetType(pc, jac->type));
37253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37260971522cSBarry Smith }
3727