xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision f5b9432784c352475479664714dcacbb1cf2b1b0)
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;
22*f5b94327SPierre 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. */
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>
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 
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 
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 */
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 
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]));
4639566063dSJacob Faibussowitsch           PetscCall(KSPSetDMActive(ilink->ksp, 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 
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 
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));
9399566063dSJacob Faibussowitsch         PetscCall(KSPSetDMActive(kspInner, 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));
9889566063dSJacob Faibussowitsch         PetscCall(KSPSetDMActive(jac->kspupper, 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));
10199566063dSJacob Faibussowitsch           PetscCall(KSPSetDMActive(jac->kspschur, 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 
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));
1137c9d0a0b7SPierre Jolivet     if (!A) {
1138ab1f0642SPierre Jolivet       if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(PetscMalloc1(m * (N + 1), &array));
1139ab1f0642SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1140ab1f0642SPierre Jolivet       else if (PetscMemTypeCUDA(mtype)) PetscCallCUDA(cudaMalloc((void **)&array, sizeof(PetscScalar) * m * (N + 1)));
1141ab1f0642SPierre Jolivet #endif
1142ab1f0642SPierre Jolivet #if PetscDefined(HAVE_HIP)
1143ab1f0642SPierre Jolivet       else if (PetscMemTypeHIP(mtype)) PetscCallHIP(hipMalloc((void **)&array, sizeof(PetscScalar) * m * (N + 1)));
1144ab1f0642SPierre Jolivet #endif
1145ab1f0642SPierre 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
11465becce15SPierre Jolivet       PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", (PetscObject)A));
11475becce15SPierre Jolivet       PetscCall(MatDestroy(&A));
114873716367SStefano Zampini     }
1149c9d0a0b7SPierre Jolivet   }
115073716367SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
115173716367SStefano Zampini }
115273716367SStefano Zampini 
115373716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit(PC pc)
115473716367SStefano Zampini {
115573716367SStefano Zampini   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
115673716367SStefano Zampini   PC_FieldSplitLink ilink = jac->head;
115773716367SStefano Zampini 
115873716367SStefano Zampini   PetscFunctionBegin;
115973716367SStefano Zampini   while (ilink) {
116073716367SStefano Zampini     PetscCall(KSPSetUp(ilink->ksp));
116173716367SStefano Zampini     PetscCall(KSPSetUpOnBlocks(ilink->ksp));
116273716367SStefano Zampini     ilink = ilink->next;
116373716367SStefano Zampini   }
116473716367SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
116573716367SStefano Zampini }
116673716367SStefano Zampini 
116773716367SStefano Zampini static PetscErrorCode PCSetUpOnBlocks_FieldSplit_GKB(PC pc)
116873716367SStefano Zampini {
116973716367SStefano Zampini   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
117073716367SStefano Zampini   PC_FieldSplitLink ilinkA = jac->head;
117173716367SStefano Zampini   KSP               ksp    = ilinkA->ksp;
117273716367SStefano Zampini 
117373716367SStefano Zampini   PetscFunctionBegin;
117473716367SStefano Zampini   PetscCall(KSPSetUp(ksp));
117573716367SStefano Zampini   PetscCall(KSPSetUpOnBlocks(ksp));
117673716367SStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
117773716367SStefano Zampini }
117873716367SStefano Zampini 
1179d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_Schur(PC pc, Vec x, Vec y)
1180d71ae5a4SJacob Faibussowitsch {
11813b224e63SBarry Smith   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
11823b224e63SBarry Smith   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1183443836d0SMatthew G Knepley   KSP               kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
1184d9eadc85SPierre Jolivet   Mat               AinvB = NULL;
1185ab1f0642SPierre Jolivet   PetscInt          N, P;
11863b224e63SBarry Smith 
11873b224e63SBarry Smith   PetscFunctionBegin;
1188c5d2311dSJed Brown   switch (jac->schurfactorization) {
1189c9c6ffaaSJed Brown   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
1190a04f6461SBarry Smith     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
11919566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
11929566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
11939566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
11949566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
11959566063dSJacob Faibussowitsch     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
11969566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
11979566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
11989566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
11999566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12009566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1201e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12029566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
12039566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
1204e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12059566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12069566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->y, jac->schurscale));
12079566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12089566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12099566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1210c5d2311dSJed Brown     break;
1211c9c6ffaaSJed Brown   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
1212a04f6461SBarry Smith     /* [A00 0; A10 S], suitable for left preconditioning */
12139566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12149566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12159566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12169566063dSJacob Faibussowitsch     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
12179566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
12189566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12199566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x));
12209566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->x, -1.));
12219566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
12229566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12239566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
12249566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1225e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12269566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1227e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12289566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
12299566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12309566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12319566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12329566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1233c5d2311dSJed Brown     break;
1234c9c6ffaaSJed Brown   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
1235a04f6461SBarry Smith     /* [A00 A01; 0 S], suitable for right preconditioning */
12369566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12379566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
12389566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1239e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
12409566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1241e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
12429566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
12439371c9d4SSatish Balay     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
12449371c9d4SSatish Balay     PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x));
12459566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkA->x, -1.));
12469566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
12479566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12489566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
12499566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12509566063dSJacob Faibussowitsch     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
12519566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
12529566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
12539566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
12549566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
12559566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1256c5d2311dSJed Brown     break;
1257c9c6ffaaSJed Brown   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
1258c238f8cdSStefano Zampini     /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */
1259ab1f0642SPierre Jolivet     PetscCall(MatGetSize(jac->B, NULL, &P));
1260ab1f0642SPierre Jolivet     N = P;
12619566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12629566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
12639566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL));
1264d9eadc85SPierre Jolivet     if (kspUpper == kspA) {
1265d9eadc85SPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&AinvB));
1266d9eadc85SPierre Jolivet       if (AinvB) {
1267d9eadc85SPierre Jolivet         PetscCall(MatGetSize(AinvB, NULL, &N));
1268ab1f0642SPierre Jolivet         if (N > P) { // first time PCApply_FieldSplit_Schur() is called
1269f7cbcdf3SPierre Jolivet           PetscMemType mtype;
1270ab1f0642SPierre Jolivet           Vec          c = NULL;
1271f7cbcdf3SPierre Jolivet           PetscScalar *array;
1272ab1f0642SPierre Jolivet           PetscInt     m, M;
1273d9eadc85SPierre Jolivet 
1274ab1f0642SPierre Jolivet           PetscCall(MatGetSize(jac->B, &M, NULL));
1275d9eadc85SPierre Jolivet           PetscCall(MatGetLocalSize(jac->B, &m, NULL));
1276ab1f0642SPierre Jolivet           PetscCall(MatDenseGetArrayAndMemType(AinvB, &array, &mtype));
1277ab1f0642SPierre Jolivet           if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1278f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1279ab1f0642SPierre Jolivet           else if (PetscMemTypeCUDA(mtype)) PetscCall(VecCreateMPICUDAWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1280f7cbcdf3SPierre Jolivet #endif
1281f7cbcdf3SPierre Jolivet #if PetscDefined(HAVE_HIP)
1282ab1f0642SPierre Jolivet           else if (PetscMemTypeHIP(mtype)) PetscCall(VecCreateMPIHIPWithArray(PetscObjectComm((PetscObject)jac->schur), 1, m, M, array + m * P, &c));
1283f7cbcdf3SPierre Jolivet #endif
1284ab1f0642SPierre Jolivet           PetscCall(MatDenseRestoreArrayAndMemType(AinvB, &array));
1285ab1f0642SPierre Jolivet           PetscCall(VecCopy(ilinkA->x, c));
1286d9eadc85SPierre Jolivet           PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
1287d9eadc85SPierre Jolivet           PetscCall(KSPSetOperators(jac->kspschur, jac->schur, jac->schur_user));
1288f7cbcdf3SPierre Jolivet           PetscCall(VecCopy(c, ilinkA->y)); // retrieve the solution as the last column of the composed Mat
1289f7cbcdf3SPierre Jolivet           PetscCall(VecDestroy(&c));
1290d9eadc85SPierre Jolivet         }
1291d9eadc85SPierre Jolivet       }
1292d9eadc85SPierre Jolivet     }
1293ab1f0642SPierre Jolivet     if (N == P) PetscCall(KSPSolve(kspLower, ilinkA->x, ilinkA->y));
12949566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->y));
12959566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL));
12969566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x));
12979566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->x, -1.0));
12989566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
12999566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
13003b224e63SBarry Smith 
13019566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1302e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
13039566063dSJacob Faibussowitsch     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1304e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
13059566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
13069566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
13079566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
13083b224e63SBarry Smith 
1309443836d0SMatthew G Knepley     if (kspUpper == kspA) {
1310d9eadc85SPierre Jolivet       if (!AinvB) {
13119566063dSJacob Faibussowitsch         PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->y));
13129566063dSJacob Faibussowitsch         PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y));
13139566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
13149566063dSJacob Faibussowitsch         PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
13159566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
13169566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1317d9eadc85SPierre Jolivet       } else PetscCall(MatMultAdd(AinvB, ilinkD->y, ilinkA->y, ilinkA->y));
1318443836d0SMatthew G Knepley     } else {
13199566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
13209566063dSJacob Faibussowitsch       PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
13219566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
13229566063dSJacob Faibussowitsch       PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x));
13239566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL));
13249566063dSJacob Faibussowitsch       PetscCall(KSPSolve(kspUpper, ilinkA->x, ilinkA->z));
13259566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->z));
13269566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL));
13279566063dSJacob Faibussowitsch       PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z));
1328443836d0SMatthew G Knepley     }
13299566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
13309566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
13319566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1332c5d2311dSJed Brown   }
13333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13343b224e63SBarry Smith }
13353b224e63SBarry Smith 
1336d484b384SBoris Martin /*
1337d484b384SBoris Martin   PCFieldSplitCreateWorkMats_Private - Allocate per-field dense work matrices for multi-RHS
1338d484b384SBoris Martin 
1339d484b384SBoris Martin   Input Parameters:
1340d484b384SBoris Martin + pc - the PC context
1341d484b384SBoris Martin - X  - matrix to copy column-layout from
1342d484b384SBoris Martin 
1343d484b384SBoris Martin   Notes:
1344d484b384SBoris Martin   If matrices already exist with correct column count, they are reused.
1345d484b384SBoris Martin   If column count changed, old matrices are destroyed and new ones created.
1346d484b384SBoris Martin */
1347d484b384SBoris Martin static PetscErrorCode PCFieldSplitCreateWorkMats_Private(PC pc, Mat X)
1348d484b384SBoris Martin {
1349d484b384SBoris Martin   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1350d484b384SBoris Martin   PC_FieldSplitLink ilink = jac->head;
1351d484b384SBoris Martin   PetscInt          mx, Mx, my, My, N;
1352d484b384SBoris Martin 
1353d484b384SBoris Martin   PetscFunctionBegin;
1354d484b384SBoris Martin   while (ilink) {
1355d484b384SBoris Martin     /* check if reallocation needed (previous allocation with wrong column count) */
1356d484b384SBoris Martin     if (ilink->X) {
1357d484b384SBoris Martin       PetscCall(MatGetSize(ilink->X, NULL, &N));
1358d484b384SBoris Martin       if (N != X->cmap->N) {
1359d484b384SBoris Martin         PetscCall(MatDestroy(&ilink->X));
1360d484b384SBoris Martin         PetscCall(MatDestroy(&ilink->Y));
1361*f5b94327SPierre Jolivet         PetscCall(MatDestroy(&ilink->Z));
1362d484b384SBoris Martin       }
1363d484b384SBoris Martin     }
1364d484b384SBoris Martin     /* create if needed */
1365d484b384SBoris Martin     if (!ilink->X) {
1366d484b384SBoris Martin       VecType xtype, ytype;
1367d484b384SBoris Martin 
1368d484b384SBoris Martin       PetscCall(VecGetType(ilink->x, &xtype));
1369d484b384SBoris Martin       PetscCall(VecGetType(ilink->y, &ytype));
1370d484b384SBoris Martin       PetscCall(VecGetLocalSize(ilink->x, &mx));
1371d484b384SBoris Martin       PetscCall(VecGetSize(ilink->x, &Mx));
1372d484b384SBoris Martin       PetscCall(VecGetLocalSize(ilink->y, &my));
1373d484b384SBoris Martin       PetscCall(VecGetSize(ilink->y, &My));
1374d484b384SBoris Martin       /* use default lda */
1375d484b384SBoris Martin       PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), xtype, mx, X->cmap->n, Mx, X->cmap->N, -1, NULL, &ilink->X));
1376d484b384SBoris Martin       PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), ytype, my, X->cmap->n, My, X->cmap->N, -1, NULL, &ilink->Y));
1377d484b384SBoris Martin     }
1378d484b384SBoris Martin     ilink = ilink->next;
1379d484b384SBoris Martin   }
1380d484b384SBoris Martin   PetscFunctionReturn(PETSC_SUCCESS);
1381d484b384SBoris Martin }
1382d484b384SBoris Martin 
1383*f5b94327SPierre Jolivet static PetscErrorCode PCMatApply_FieldSplit_Schur(PC pc, Mat X, Mat Y)
1384*f5b94327SPierre Jolivet {
1385*f5b94327SPierre Jolivet   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
1386*f5b94327SPierre Jolivet   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1387*f5b94327SPierre Jolivet   KSP               kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
1388*f5b94327SPierre Jolivet   Mat               AinvB = NULL;
1389*f5b94327SPierre Jolivet   PetscInt          N, P;
1390*f5b94327SPierre Jolivet 
1391*f5b94327SPierre Jolivet   PetscFunctionBegin;
1392*f5b94327SPierre Jolivet   /* create working matrices with the correct number of columns */
1393*f5b94327SPierre Jolivet   PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X));
1394*f5b94327SPierre Jolivet   switch (jac->schurfactorization) {
1395*f5b94327SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
1396*f5b94327SPierre Jolivet     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
1397*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1398*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, INSERT_VALUES, SCATTER_FORWARD));
1399*f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1400*f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1401*f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1402*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1403*f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1404*f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1405*f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1406*f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1407*f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1408*f5b94327SPierre Jolivet     PetscCall(MatScale(ilinkD->Y, jac->schurscale));
1409*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1410*f5b94327SPierre Jolivet     break;
1411*f5b94327SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
1412*f5b94327SPierre Jolivet     /* [A00 0; A10 S], suitable for left preconditioning */
1413*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1414*f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1415*f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1416*f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1417*f5b94327SPierre Jolivet     PetscCall(MatMatMult(jac->C, ilinkA->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkD->X));
1418*f5b94327SPierre Jolivet     PetscCall(MatScale(ilinkD->X, -1.0));
1419*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, ADD_VALUES, SCATTER_FORWARD));
1420*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1421*f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1422*f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1423*f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1424*f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1425*f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1426*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1427*f5b94327SPierre Jolivet     break;
1428*f5b94327SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
1429*f5b94327SPierre Jolivet     /* [A00 A01; 0 S], suitable for right preconditioning */
1430*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, INSERT_VALUES, SCATTER_FORWARD));
1431*f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1432*f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1433*f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1434*f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1435*f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1436*f5b94327SPierre Jolivet     PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1437*f5b94327SPierre Jolivet     PetscCall(MatScale(ilinkA->X, -1.0));
1438*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, ADD_VALUES, SCATTER_FORWARD));
1439*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1440*f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1441*f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1442*f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1443*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1444*f5b94327SPierre Jolivet     break;
1445*f5b94327SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
1446*f5b94327SPierre Jolivet     /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */
1447*f5b94327SPierre Jolivet     PetscCall(MatGetSize(jac->B, NULL, &P));
1448*f5b94327SPierre Jolivet     N = P;
1449*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, X, ilinkA->X, INSERT_VALUES, SCATTER_FORWARD));
1450*f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->X, ilinkA->Y, NULL));
1451*f5b94327SPierre Jolivet     if (kspUpper == kspA) {
1452*f5b94327SPierre Jolivet       PetscCall(PetscObjectQuery((PetscObject)jac->schur, "AinvB", (PetscObject *)&AinvB));
1453*f5b94327SPierre Jolivet       if (AinvB) {
1454*f5b94327SPierre Jolivet         PetscCall(MatGetSize(AinvB, NULL, &N));
1455*f5b94327SPierre Jolivet         if (N > P) { // first time PCApply_FieldSplit_Schur() is called
1456*f5b94327SPierre Jolivet           PetscMemType mtype;
1457*f5b94327SPierre Jolivet           Mat          C = NULL;
1458*f5b94327SPierre Jolivet           PetscScalar *array;
1459*f5b94327SPierre Jolivet           PetscInt     m, M, q, Q, p;
1460*f5b94327SPierre Jolivet 
1461*f5b94327SPierre Jolivet           PetscCall(MatGetSize(jac->B, &M, NULL));
1462*f5b94327SPierre Jolivet           PetscCall(MatGetLocalSize(jac->B, &m, NULL));
1463*f5b94327SPierre Jolivet           PetscCall(MatGetSize(X, NULL, &Q));
1464*f5b94327SPierre Jolivet           PetscCall(MatGetLocalSize(X, NULL, &q));
1465*f5b94327SPierre Jolivet           PetscCall(MatDenseGetArrayAndMemType(AinvB, &array, &mtype));
1466*f5b94327SPierre Jolivet           if (N != P + Q) {
1467*f5b94327SPierre Jolivet             Mat replace;
1468*f5b94327SPierre Jolivet 
1469*f5b94327SPierre Jolivet             PetscCall(MatGetLocalSize(jac->B, NULL, &p));
1470*f5b94327SPierre Jolivet             if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) {
1471*f5b94327SPierre Jolivet               PetscCall(PetscFree(array));
1472*f5b94327SPierre Jolivet               PetscCall(PetscMalloc1(m * (P + Q), &array));
1473*f5b94327SPierre Jolivet               PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1474*f5b94327SPierre Jolivet             }
1475*f5b94327SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1476*f5b94327SPierre Jolivet             else if (PetscMemTypeCUDA(mtype)) {
1477*f5b94327SPierre Jolivet               PetscCallCUDA(cudaFree(array));
1478*f5b94327SPierre Jolivet               PetscCallCUDA(cudaMalloc((void **)&array, sizeof(PetscScalar) * m * (P + Q)));
1479*f5b94327SPierre Jolivet               PetscCall(MatCreateDenseCUDA(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1480*f5b94327SPierre Jolivet             }
1481*f5b94327SPierre Jolivet #endif
1482*f5b94327SPierre Jolivet #if PetscDefined(HAVE_HIP)
1483*f5b94327SPierre Jolivet             else if (PetscMemTypeHIP(mtype)) {
1484*f5b94327SPierre Jolivet               PetscCallHIP(hipFree(array));
1485*f5b94327SPierre Jolivet               PetscCallHIP(hipMalloc((void **)&array, sizeof(PetscScalar) * m * (P + Q)));
1486*f5b94327SPierre Jolivet               PetscCall(MatCreateDenseHIP(PetscObjectComm((PetscObject)jac->schur), m, PETSC_DECIDE, M, P + Q, array, &replace));
1487*f5b94327SPierre Jolivet             }
1488*f5b94327SPierre Jolivet #endif
1489*f5b94327SPierre Jolivet             PetscCall(MatHeaderReplace(AinvB, &replace));
1490*f5b94327SPierre Jolivet           }
1491*f5b94327SPierre Jolivet           if (PetscMemTypeHost(mtype) || (!PetscDefined(HAVE_CUDA) && !PetscDefined(HAVE_HIP))) PetscCall(MatCreateDense(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1492*f5b94327SPierre Jolivet #if PetscDefined(HAVE_CUDA)
1493*f5b94327SPierre Jolivet           else if (PetscMemTypeCUDA(mtype)) PetscCall(MatCreateDenseCUDA(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1494*f5b94327SPierre Jolivet #endif
1495*f5b94327SPierre Jolivet #if PetscDefined(HAVE_HIP)
1496*f5b94327SPierre Jolivet           else if (PetscMemTypeHIP(mtype)) PetscCall(MatCreateDenseHIP(PetscObjectComm((PetscObject)jac->schur), m, q, M, Q, array + m * P, &C));
1497*f5b94327SPierre Jolivet #endif
1498*f5b94327SPierre Jolivet           PetscCall(MatDenseRestoreArrayAndMemType(AinvB, &array));
1499*f5b94327SPierre Jolivet           PetscCall(MatCopy(ilinkA->X, C, SAME_NONZERO_PATTERN));
1500*f5b94327SPierre Jolivet           PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
1501*f5b94327SPierre Jolivet           PetscCall(KSPSetOperators(jac->kspschur, jac->schur, jac->schur_user));
1502*f5b94327SPierre Jolivet           PetscCall(MatCopy(C, ilinkA->Y, SAME_NONZERO_PATTERN)); // retrieve solutions as last columns of the composed Mat
1503*f5b94327SPierre Jolivet           PetscCall(MatDestroy(&C));
1504*f5b94327SPierre Jolivet         }
1505*f5b94327SPierre Jolivet       }
1506*f5b94327SPierre Jolivet     }
1507*f5b94327SPierre Jolivet     if (N == P) PetscCall(KSPMatSolve(kspLower, ilinkA->X, ilinkA->Y));
1508*f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->X, ilinkA->Y, NULL));
1509*f5b94327SPierre Jolivet     PetscCall(MatMatMult(jac->C, ilinkA->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkD->X));
1510*f5b94327SPierre Jolivet     PetscCall(MatScale(ilinkD->X, -1.0));
1511*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, X, ilinkD->X, ADD_VALUES, SCATTER_FORWARD));
1512*f5b94327SPierre Jolivet 
1513*f5b94327SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1514*f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
1515*f5b94327SPierre Jolivet     PetscCall(KSPMatSolve(jac->kspschur, ilinkD->X, ilinkD->Y));
1516*f5b94327SPierre Jolivet     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
1517*f5b94327SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->X, ilinkD->Y, NULL));
1518*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkD->sctx, ilinkD->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1519*f5b94327SPierre Jolivet 
1520*f5b94327SPierre Jolivet     if (kspUpper == kspA) {
1521*f5b94327SPierre Jolivet       if (!AinvB) {
1522*f5b94327SPierre Jolivet         PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->Y));
1523*f5b94327SPierre Jolivet         PetscCall(MatAXPY(ilinkA->X, -1.0, ilinkA->Y, SAME_NONZERO_PATTERN));
1524*f5b94327SPierre Jolivet         PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1525*f5b94327SPierre Jolivet         PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1526*f5b94327SPierre Jolivet         PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1527*f5b94327SPierre Jolivet       } else {
1528*f5b94327SPierre Jolivet         PetscCall(MatMatMult(AinvB, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1529*f5b94327SPierre Jolivet         PetscCall(MatAXPY(ilinkA->Y, 1.0, ilinkA->X, SAME_NONZERO_PATTERN));
1530*f5b94327SPierre Jolivet       }
1531*f5b94327SPierre Jolivet     } else {
1532*f5b94327SPierre Jolivet       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->X, ilinkA->Y, NULL));
1533*f5b94327SPierre Jolivet       PetscCall(KSPMatSolve(kspA, ilinkA->X, ilinkA->Y));
1534*f5b94327SPierre Jolivet       PetscCall(MatMatMult(jac->B, ilinkD->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilinkA->X));
1535*f5b94327SPierre Jolivet       if (!ilinkA->Z) PetscCall(MatDuplicate(ilinkA->X, MAT_DO_NOT_COPY_VALUES, &ilinkA->Z));
1536*f5b94327SPierre Jolivet       PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->X, ilinkA->Z, NULL));
1537*f5b94327SPierre Jolivet       PetscCall(KSPMatSolve(kspUpper, ilinkA->X, ilinkA->Z));
1538*f5b94327SPierre Jolivet       PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->X, ilinkA->Z, NULL));
1539*f5b94327SPierre Jolivet       PetscCall(MatAXPY(ilinkA->Y, -1.0, ilinkA->Z, SAME_NONZERO_PATTERN));
1540*f5b94327SPierre Jolivet     }
1541*f5b94327SPierre Jolivet     PetscCall(MatDenseScatter_Private(ilinkA->sctx, ilinkA->Y, Y, INSERT_VALUES, SCATTER_REVERSE));
1542*f5b94327SPierre Jolivet   }
1543*f5b94327SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
1544*f5b94327SPierre Jolivet }
1545*f5b94327SPierre Jolivet 
15467b665727SPierre Jolivet static PetscErrorCode PCApplyTranspose_FieldSplit_Schur(PC pc, Vec x, Vec y)
15477b665727SPierre Jolivet {
15487b665727SPierre Jolivet   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
15497b665727SPierre Jolivet   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
15507b665727SPierre Jolivet   KSP               kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
15517b665727SPierre Jolivet 
15527b665727SPierre Jolivet   PetscFunctionBegin;
15537b665727SPierre Jolivet   switch (jac->schurfactorization) {
15547b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
15557b665727SPierre Jolivet     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
15567b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15577b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
15587b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15597b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15607b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
15617b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
15627b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15637b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15647b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
15657b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1566e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
15677b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1568e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
15697b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
15707b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
15717b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->y, jac->schurscale));
15727b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15737b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
15747b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
15757b665727SPierre Jolivet     break;
15767b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
15777b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15787b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
15797b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15807b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
15817b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
15827b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
15837b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x));
15847b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->x, -1.));
15857b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
15867b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15877b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
15887b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1589e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
15907b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1591e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
15927b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
15937b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
15947b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
15957b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
15967b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
15977b665727SPierre Jolivet     break;
15987b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
15997b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
16007b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
16017b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1602e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
16037b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1604e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
16057b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
16067b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
16077b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x));
16087b665727SPierre Jolivet     PetscCall(VecScale(ilinkA->x, -1.));
16097b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
16107b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16117b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
16127b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16137b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16147b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16157b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16167b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16177b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16187b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16197b665727SPierre Jolivet     break;
16207b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
16217b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
16227b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
16237b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL));
16247b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspUpper, ilinkA->x, ilinkA->y));
16257b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->y));
16267b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL));
16277b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x));
16287b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->x, -1.0));
16297b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
16307b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
16317b665727SPierre Jolivet 
16327b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1633e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
16347b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1635e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
16367b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
16377b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
16387b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16397b665727SPierre Jolivet 
16407b665727SPierre Jolivet     if (kspLower == kspA) {
16417b665727SPierre Jolivet       PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->y));
16427b665727SPierre Jolivet       PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y));
16437b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16447b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16457b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16467b665727SPierre Jolivet       PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16477b665727SPierre Jolivet     } else {
16487b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
16497b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
16507b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
16517b665727SPierre Jolivet       PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x));
16527b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL));
16537b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspLower, ilinkA->x, ilinkA->z));
16547b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->z));
16557b665727SPierre Jolivet       PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL));
16567b665727SPierre Jolivet       PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z));
16577b665727SPierre Jolivet     }
16587b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
16597b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16607b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
16617b665727SPierre Jolivet   }
16627b665727SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
16637b665727SPierre Jolivet }
16647b665727SPierre Jolivet 
16655becce15SPierre Jolivet #define FieldSplitSplitSolveAdd(ilink, xx, yy) \
16665becce15SPierre 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) || \
16675becce15SPierre 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) || \
16685becce15SPierre Jolivet                     VecScatterEnd(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE)))
16695becce15SPierre Jolivet 
1670d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit(PC pc, Vec x, Vec y)
1671d71ae5a4SJacob Faibussowitsch {
16720971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
16735a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
1674939b8a20SBarry Smith   PetscInt          cnt, bs;
16750971522cSBarry Smith 
16760971522cSBarry Smith   PetscFunctionBegin;
167779416396SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
167880670ca5SBarry Smith     PetscBool matnest;
167980670ca5SBarry Smith 
168080670ca5SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
168180670ca5SBarry Smith     if (jac->defaultsplit && !matnest) {
16829566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(x, &bs));
16832472a847SBarry 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);
16849566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(y, &bs));
16852472a847SBarry 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);
16869566063dSJacob Faibussowitsch       PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
16875a9f2f41SSatish Balay       while (ilink) {
16889566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
16899566063dSJacob Faibussowitsch         PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
16909566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
16919566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
16925a9f2f41SSatish Balay         ilink = ilink->next;
16930971522cSBarry Smith       }
16949566063dSJacob Faibussowitsch       PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
16951b9fc7fcSBarry Smith     } else {
16969566063dSJacob Faibussowitsch       PetscCall(VecSet(y, 0.0));
16975a9f2f41SSatish Balay       while (ilink) {
16989566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
16995a9f2f41SSatish Balay         ilink = ilink->next;
17001b9fc7fcSBarry Smith       }
17011b9fc7fcSBarry Smith     }
1702e52d2c62SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
17039566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
1704e52d2c62SBarry Smith     /* solve on first block for first block variables */
17059566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
17069566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
17079566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17089566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17099566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17109566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17119566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17129566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1713e52d2c62SBarry Smith 
1714e52d2c62SBarry Smith     /* compute the residual only onto second block variables using first block variables */
17159566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->Afield[1], ilink->y, ilink->next->x));
1716e52d2c62SBarry Smith     ilink = ilink->next;
17179566063dSJacob Faibussowitsch     PetscCall(VecScale(ilink->x, -1.0));
17189566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17199566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1720e52d2c62SBarry Smith 
1721e52d2c62SBarry Smith     /* solve on second block variables */
17229566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17239566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17249566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17259566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17269566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17279566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
172816913363SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
172979416396SBarry Smith     if (!jac->w1) {
17309566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w1));
17319566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w2));
173279416396SBarry Smith     }
17339566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
17349566063dSJacob Faibussowitsch     PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
17353e197d65SBarry Smith     cnt = 1;
17365a9f2f41SSatish Balay     while (ilink->next) {
17375a9f2f41SSatish Balay       ilink = ilink->next;
17383e197d65SBarry Smith       /* compute the residual only over the part of the vector needed */
17399566063dSJacob Faibussowitsch       PetscCall(MatMult(jac->Afield[cnt++], y, ilink->x));
17409566063dSJacob Faibussowitsch       PetscCall(VecScale(ilink->x, -1.0));
17419566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17429566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17439566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17449566063dSJacob Faibussowitsch       PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17459566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17469566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17479566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17489566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17493e197d65SBarry Smith     }
175051f519a2SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
175111755939SBarry Smith       cnt -= 2;
175251f519a2SBarry Smith       while (ilink->previous) {
175351f519a2SBarry Smith         ilink = ilink->previous;
175411755939SBarry Smith         /* compute the residual only over the part of the vector needed */
17559566063dSJacob Faibussowitsch         PetscCall(MatMult(jac->Afield[cnt--], y, ilink->x));
17569566063dSJacob Faibussowitsch         PetscCall(VecScale(ilink->x, -1.0));
17579566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17589566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
17599566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17609566063dSJacob Faibussowitsch         PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
17619566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
17629566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
17639566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
17649566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
176551f519a2SBarry Smith       }
176611755939SBarry Smith     }
176763a3b9bcSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)jac->type);
17683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17690971522cSBarry Smith }
17700971522cSBarry Smith 
1771d484b384SBoris Martin static PetscErrorCode PCMatApply_FieldSplit(PC pc, Mat X, Mat Y)
1772d484b384SBoris Martin {
1773d484b384SBoris Martin   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1774d484b384SBoris Martin   PC_FieldSplitLink ilink = jac->head;
1775d484b384SBoris Martin   PetscInt          cnt;
1776d484b384SBoris Martin 
1777d484b384SBoris Martin   PetscFunctionBegin;
1778d484b384SBoris Martin   /* create working matrices with the correct number of columns */
1779d484b384SBoris Martin   PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X));
1780d484b384SBoris Martin   if (jac->type == PC_COMPOSITE_ADDITIVE) {
1781d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
1782d484b384SBoris Martin     while (ilink) {
1783d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1784d484b384SBoris Martin       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1785d484b384SBoris Martin       PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1786d484b384SBoris Martin       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1787d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1788d484b384SBoris Martin       ilink = ilink->next;
1789d484b384SBoris Martin     }
1790d484b384SBoris Martin   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
1791d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
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 
1798d484b384SBoris Martin     /* compute the residual only onto second block variables using first block variables */
1799d484b384SBoris Martin     PetscCall(MatMatMult(jac->Afield[1], ilink->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->next->X));
1800d484b384SBoris Martin     ilink = ilink->next;
1801d484b384SBoris Martin     PetscCall(MatScale(ilink->X, -1.0));
1802d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1803d484b384SBoris Martin 
1804d484b384SBoris Martin     /* solve on second block variables */
1805d484b384SBoris Martin     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1806d484b384SBoris Martin     PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1807d484b384SBoris Martin     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1808d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1809d484b384SBoris Martin   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1810d484b384SBoris Martin     /* general multiplicative with any number of splits */
1811d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
1812d484b384SBoris Martin     /* first split */
1813d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
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     cnt = 1;
1819d484b384SBoris Martin     /* forward sweep */
1820d484b384SBoris Martin     while (ilink->next) {
1821d484b384SBoris Martin       ilink = ilink->next;
1822d484b384SBoris Martin       /* compute the residual only over the part of the vector needed */
1823d484b384SBoris Martin       PetscCall(MatMatMult(jac->Afield[cnt++], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X));
1824d484b384SBoris Martin       PetscCall(MatScale(ilink->X, -1.0));
1825d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1826d484b384SBoris Martin       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1827d484b384SBoris Martin       PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1828d484b384SBoris Martin       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1829d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1830d484b384SBoris Martin     }
1831d484b384SBoris Martin     /* backward sweep for symmetric multiplicative */
1832d484b384SBoris Martin     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1833d484b384SBoris Martin       cnt -= 2;
1834d484b384SBoris Martin       while (ilink->previous) {
1835d484b384SBoris Martin         ilink = ilink->previous;
1836d484b384SBoris Martin         /* compute the residual only over the part of the vector needed */
1837d484b384SBoris Martin         PetscCall(MatMatMult(jac->Afield[cnt--], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X));
1838d484b384SBoris Martin         PetscCall(MatScale(ilink->X, -1.0));
1839d484b384SBoris Martin         PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1840d484b384SBoris Martin         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1841d484b384SBoris Martin         PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1842d484b384SBoris Martin         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1843d484b384SBoris Martin         PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1844d484b384SBoris Martin       }
1845d484b384SBoris Martin     }
1846d484b384SBoris Martin   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCMatApply() not implemented for this fieldsplit type");
1847d484b384SBoris Martin   PetscFunctionReturn(PETSC_SUCCESS);
1848d484b384SBoris Martin }
1849d484b384SBoris Martin 
1850d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_GKB(PC pc, Vec x, Vec y)
1851d71ae5a4SJacob Faibussowitsch {
1852a51937d4SCarola Kruse   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
1853a51937d4SCarola Kruse   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1854a51937d4SCarola Kruse   KSP               ksp = ilinkA->ksp;
1855de482cd7SCarola Kruse   Vec               u, v, Hu, d, work1, work2;
1856e071a0a4SCarola Kruse   PetscScalar       alpha, z, nrmz2, *vecz;
1857e071a0a4SCarola Kruse   PetscReal         lowbnd, nu, beta;
1858a51937d4SCarola Kruse   PetscInt          j, iterGKB;
1859a51937d4SCarola Kruse 
1860a51937d4SCarola Kruse   PetscFunctionBegin;
18619566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
18629566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
18639566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
18649566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1865e071a0a4SCarola Kruse 
1866e071a0a4SCarola Kruse   u     = jac->u;
1867e071a0a4SCarola Kruse   v     = jac->v;
1868e071a0a4SCarola Kruse   Hu    = jac->Hu;
1869e071a0a4SCarola Kruse   d     = jac->d;
1870e071a0a4SCarola Kruse   work1 = jac->w1;
1871e071a0a4SCarola Kruse   work2 = jac->w2;
1872e071a0a4SCarola Kruse   vecz  = jac->vecz;
1873a51937d4SCarola Kruse 
1874a51937d4SCarola Kruse   /* Change RHS to comply with matrix regularization H = A + nu*B*B' */
1875a51937d4SCarola Kruse   /* Add q = q + nu*B*b */
1876a51937d4SCarola Kruse   if (jac->gkbnu) {
1877a51937d4SCarola Kruse     nu = jac->gkbnu;
18789566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->x, jac->gkbnu));
18799566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(jac->B, ilinkD->x, ilinkA->x, ilinkA->x)); /* q = q + nu*B*b */
1880a51937d4SCarola Kruse   } else {
1881a51937d4SCarola Kruse     /* Situation when no augmented Lagrangian is used. Then we set inner  */
1882a51937d4SCarola Kruse     /* matrix N = I in [Ar13], and thus nu = 1.                           */
1883a51937d4SCarola Kruse     nu = 1;
1884a51937d4SCarola Kruse   }
1885a51937d4SCarola Kruse 
1886a51937d4SCarola Kruse   /* Transform rhs from [q,tilde{b}] to [0,b] */
18879566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
18889566063dSJacob Faibussowitsch   PetscCall(KSPSolve(ksp, ilinkA->x, ilinkA->y));
18899566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(ksp, pc, ilinkA->y));
18909566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
18919566063dSJacob Faibussowitsch   PetscCall(MatMultHermitianTranspose(jac->B, ilinkA->y, work1));
18929566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(work1, 1.0 / nu, -1.0, ilinkD->x)); /* c = b - B'*x        */
1893a51937d4SCarola Kruse 
1894a51937d4SCarola Kruse   /* First step of algorithm */
18959566063dSJacob Faibussowitsch   PetscCall(VecNorm(work1, NORM_2, &beta)); /* beta = sqrt(nu*c'*c)*/
1896e071a0a4SCarola Kruse   KSPCheckDot(ksp, beta);
1897addd1e01SJunchao Zhang   beta = PetscSqrtReal(nu) * beta;
18989566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(v, nu / beta, 0.0, work1)); /* v = nu/beta *c      */
18999566063dSJacob Faibussowitsch   PetscCall(MatMult(jac->B, v, work2));          /* u = H^{-1}*B*v      */
19009566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
19019566063dSJacob Faibussowitsch   PetscCall(KSPSolve(ksp, work2, u));
19029566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(ksp, pc, u));
19039566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
19049566063dSJacob Faibussowitsch   PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u      */
19059566063dSJacob Faibussowitsch   PetscCall(VecDot(Hu, u, &alpha));
1906e071a0a4SCarola Kruse   KSPCheckDot(ksp, alpha);
190708401ef6SPierre Jolivet   PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1908addd1e01SJunchao Zhang   alpha = PetscSqrtReal(PetscAbsScalar(alpha));
19099566063dSJacob Faibussowitsch   PetscCall(VecScale(u, 1.0 / alpha));
19109566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(d, 1.0 / alpha, 0.0, v)); /* v = nu/beta *c      */
1911de482cd7SCarola Kruse 
1912a51937d4SCarola Kruse   z       = beta / alpha;
1913a51937d4SCarola Kruse   vecz[1] = z;
1914a51937d4SCarola Kruse 
1915de482cd7SCarola Kruse   /* Computation of first iterate x(1) and p(1) */
19169566063dSJacob Faibussowitsch   PetscCall(VecAXPY(ilinkA->y, z, u));
19179566063dSJacob Faibussowitsch   PetscCall(VecCopy(d, ilinkD->y));
19189566063dSJacob Faibussowitsch   PetscCall(VecScale(ilinkD->y, -z));
1919a51937d4SCarola Kruse 
19209371c9d4SSatish Balay   iterGKB = 1;
19219371c9d4SSatish Balay   lowbnd  = 2 * jac->gkbtol;
192248a46eb9SPierre Jolivet   if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1923de482cd7SCarola Kruse 
1924a51937d4SCarola Kruse   while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) {
1925a51937d4SCarola Kruse     iterGKB += 1;
19269566063dSJacob Faibussowitsch     PetscCall(MatMultHermitianTranspose(jac->B, u, work1)); /* v <- nu*(B'*u-alpha/nu*v) */
19279566063dSJacob Faibussowitsch     PetscCall(VecAXPBY(v, nu, -alpha, work1));
19289566063dSJacob Faibussowitsch     PetscCall(VecNorm(v, NORM_2, &beta)); /* beta = sqrt(nu)*v'*v      */
1929addd1e01SJunchao Zhang     beta = beta / PetscSqrtReal(nu);
19309566063dSJacob Faibussowitsch     PetscCall(VecScale(v, 1.0 / beta));
19319566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->B, v, work2)); /* u <- H^{-1}*(B*v-beta*H*u) */
19329566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, u, Hu));
19339566063dSJacob Faibussowitsch     PetscCall(VecAXPY(work2, -beta, Hu));
19349566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
19359566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ksp, work2, u));
19369566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ksp, pc, u));
19379566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
19389566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u            */
19399566063dSJacob Faibussowitsch     PetscCall(VecDot(Hu, u, &alpha));
1940e071a0a4SCarola Kruse     KSPCheckDot(ksp, alpha);
194108401ef6SPierre Jolivet     PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1942addd1e01SJunchao Zhang     alpha = PetscSqrtReal(PetscAbsScalar(alpha));
19439566063dSJacob Faibussowitsch     PetscCall(VecScale(u, 1.0 / alpha));
1944a51937d4SCarola Kruse 
1945e071a0a4SCarola Kruse     z       = -beta / alpha * z; /* z <- beta/alpha*z     */
1946a51937d4SCarola Kruse     vecz[0] = z;
1947a51937d4SCarola Kruse 
1948a51937d4SCarola Kruse     /* Computation of new iterate x(i+1) and p(i+1) */
19499566063dSJacob Faibussowitsch     PetscCall(VecAXPBY(d, 1.0 / alpha, -beta / alpha, v)); /* d = (v-beta*d)/alpha */
19509566063dSJacob Faibussowitsch     PetscCall(VecAXPY(ilinkA->y, z, u));                   /* r = r + z*u          */
19519566063dSJacob Faibussowitsch     PetscCall(VecAXPY(ilinkD->y, -z, d));                  /* p = p - z*d          */
19529566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, ilinkA->y, Hu));             /* ||u||_H = u'*H*u     */
19539566063dSJacob Faibussowitsch     PetscCall(VecDot(Hu, ilinkA->y, &nrmz2));
1954a51937d4SCarola Kruse 
1955a51937d4SCarola Kruse     /* Compute Lower Bound estimate */
1956a51937d4SCarola Kruse     if (iterGKB > jac->gkbdelay) {
1957a51937d4SCarola Kruse       lowbnd = 0.0;
1958ad540459SPierre Jolivet       for (j = 0; j < jac->gkbdelay; j++) lowbnd += PetscAbsScalar(vecz[j] * vecz[j]);
1959addd1e01SJunchao Zhang       lowbnd = PetscSqrtReal(lowbnd / PetscAbsScalar(nrmz2));
1960a51937d4SCarola Kruse     }
1961a51937d4SCarola Kruse 
1962ad540459SPierre Jolivet     for (j = 0; j < jac->gkbdelay - 1; j++) vecz[jac->gkbdelay - j - 1] = vecz[jac->gkbdelay - j - 2];
196348a46eb9SPierre Jolivet     if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1964a51937d4SCarola Kruse   }
1965a51937d4SCarola Kruse 
19669566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
19679566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
19689566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
19699566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
19703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1971a51937d4SCarola Kruse }
1972a51937d4SCarola Kruse 
1973421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink, xx, yy) \
19743ba16761SJacob 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) || \
19759371c9d4SSatish 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) || \
19763ba16761SJacob Faibussowitsch                     VecScatterEnd(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE)))
1977421e10b8SBarry Smith 
1978d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc, Vec x, Vec y)
1979d71ae5a4SJacob Faibussowitsch {
1980421e10b8SBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1981421e10b8SBarry Smith   PC_FieldSplitLink ilink = jac->head;
1982939b8a20SBarry Smith   PetscInt          bs;
1983421e10b8SBarry Smith 
1984421e10b8SBarry Smith   PetscFunctionBegin;
1985421e10b8SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
198680670ca5SBarry Smith     PetscBool matnest;
198780670ca5SBarry Smith 
198880670ca5SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
198980670ca5SBarry Smith     if (jac->defaultsplit && !matnest) {
19909566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(x, &bs));
19912472a847SBarry 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);
19929566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(y, &bs));
19932472a847SBarry 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);
19949566063dSJacob Faibussowitsch       PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
1995421e10b8SBarry Smith       while (ilink) {
19969566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
19979566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(ilink->ksp, ilink->x, ilink->y));
19989566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
19999566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
2000421e10b8SBarry Smith         ilink = ilink->next;
2001421e10b8SBarry Smith       }
20029566063dSJacob Faibussowitsch       PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
2003421e10b8SBarry Smith     } else {
20049566063dSJacob Faibussowitsch       PetscCall(VecSet(y, 0.0));
2005421e10b8SBarry Smith       while (ilink) {
20069566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2007421e10b8SBarry Smith         ilink = ilink->next;
2008421e10b8SBarry Smith       }
2009421e10b8SBarry Smith     }
2010421e10b8SBarry Smith   } else {
2011421e10b8SBarry Smith     if (!jac->w1) {
20129566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w1));
20139566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w2));
2014421e10b8SBarry Smith     }
20159566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
2016421e10b8SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
20179566063dSJacob Faibussowitsch       PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2018421e10b8SBarry Smith       while (ilink->next) {
2019421e10b8SBarry Smith         ilink = ilink->next;
20209566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20219566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20229566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2023421e10b8SBarry Smith       }
2024421e10b8SBarry Smith       while (ilink->previous) {
2025421e10b8SBarry Smith         ilink = ilink->previous;
20269566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20279566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20289566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2029421e10b8SBarry Smith       }
2030421e10b8SBarry Smith     } else {
2031421e10b8SBarry Smith       while (ilink->next) { /* get to last entry in linked list */
2032421e10b8SBarry Smith         ilink = ilink->next;
2033421e10b8SBarry Smith       }
20349566063dSJacob Faibussowitsch       PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
2035421e10b8SBarry Smith       while (ilink->previous) {
2036421e10b8SBarry Smith         ilink = ilink->previous;
20379566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
20389566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
20399566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
2040421e10b8SBarry Smith       }
2041421e10b8SBarry Smith     }
2042421e10b8SBarry Smith   }
20433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2044421e10b8SBarry Smith }
2045421e10b8SBarry Smith 
2046d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_FieldSplit(PC pc)
2047d71ae5a4SJacob Faibussowitsch {
20480971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
20495a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head, next;
20500971522cSBarry Smith 
20510971522cSBarry Smith   PetscFunctionBegin;
20525a9f2f41SSatish Balay   while (ilink) {
20539566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&ilink->ksp));
20549566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->x));
20559566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->y));
20569566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->z));
2057d484b384SBoris Martin     PetscCall(MatDestroy(&ilink->X));
2058d484b384SBoris Martin     PetscCall(MatDestroy(&ilink->Y));
2059*f5b94327SPierre Jolivet     PetscCall(MatDestroy(&ilink->Z));
20609566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&ilink->sctx));
20619566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is));
20629566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is_col));
20639566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->splitname));
20649566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->fields));
20659566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->fields_col));
20665a9f2f41SSatish Balay     next = ilink->next;
20679566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink));
20685a9f2f41SSatish Balay     ilink = next;
20690971522cSBarry Smith   }
2070f5f0d762SBarry Smith   jac->head = NULL;
20719566063dSJacob Faibussowitsch   PetscCall(PetscFree2(jac->x, jac->y));
2072574deadeSBarry Smith   if (jac->mat && jac->mat != jac->pmat) {
20739566063dSJacob Faibussowitsch     PetscCall(MatDestroyMatrices(jac->nsplits, &jac->mat));
2074574deadeSBarry Smith   } else if (jac->mat) {
20750298fd71SBarry Smith     jac->mat = NULL;
2076574deadeSBarry Smith   }
20779566063dSJacob Faibussowitsch   if (jac->pmat) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->pmat));
20789566063dSJacob Faibussowitsch   if (jac->Afield) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->Afield));
2079f5f0d762SBarry Smith   jac->nsplits = 0;
20809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->w1));
20819566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->w2));
208273716367SStefano Zampini   if (jac->schur) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", NULL));
20839566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schur));
20849566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schurp));
20859566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schur_user));
20869566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->kspschur));
20879566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->kspupper));
20889566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->B));
20899566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->C));
20909566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->H));
20919566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->u));
20929566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->v));
20939566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->Hu));
20949566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->d));
20959566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->vecz));
20969566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&jac->gkbviewer));
20976dbb499eSCian Wilson   jac->isrestrict = PETSC_FALSE;
20983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2099574deadeSBarry Smith }
2100574deadeSBarry Smith 
2101d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_FieldSplit(PC pc)
2102d71ae5a4SJacob Faibussowitsch {
2103574deadeSBarry Smith   PetscFunctionBegin;
21049566063dSJacob Faibussowitsch   PetscCall(PCReset_FieldSplit(pc));
21059566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
21062e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL));
21079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", NULL));
21089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL));
21099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", NULL));
21109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", NULL));
21112e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", NULL));
21122e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", NULL));
21132e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
21142e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
21152e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
21162e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
21172e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
21189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
21199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
21209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
21212e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
21223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21230971522cSBarry Smith }
21240971522cSBarry Smith 
2125ce78bad3SBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc, PetscOptionItems PetscOptionsObject)
2126d71ae5a4SJacob Faibussowitsch {
21276c924f48SJed Brown   PetscInt        bs;
21287b752e3dSPatrick Sanan   PetscBool       flg;
21299dcbbd2bSBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit *)pc->data;
21303b224e63SBarry Smith   PCCompositeType ctype;
21311b9fc7fcSBarry Smith 
21320971522cSBarry Smith   PetscFunctionBegin;
2133d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "FieldSplit options");
21349566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_fieldsplit_dm_splits", "Whether to use DMCreateFieldDecomposition() for splits", "PCFieldSplitSetDMSplits", jac->dm_splits, &jac->dm_splits, NULL));
21359566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_fieldsplit_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", jac->bs, &bs, &flg));
21361baa6e33SBarry Smith   if (flg) PetscCall(PCFieldSplitSetBlockSize(pc, bs));
21372686e3e9SMatthew G. Knepley   jac->diag_use_amat = pc->useAmat;
21389566063dSJacob 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));
21392686e3e9SMatthew G. Knepley   jac->offdiag_use_amat = pc->useAmat;
21409566063dSJacob 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));
21419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_fieldsplit_detect_saddle_point", "Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint", jac->detect, &jac->detect, NULL));
21429566063dSJacob Faibussowitsch   PetscCall(PCFieldSplitSetDetectSaddlePoint(pc, jac->detect)); /* Sets split type and Schur PC type */
21439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_fieldsplit_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&ctype, &flg));
21441baa6e33SBarry Smith   if (flg) PetscCall(PCFieldSplitSetType(pc, ctype));
2145c30613efSMatthew Knepley   /* Only setup fields once */
2146b6555650SPierre Jolivet   if (jac->bs > 0 && jac->nsplits == 0) {
214780670ca5SBarry Smith     /* only allow user to set fields from command line.
2148d32f9abdSBarry Smith        otherwise user can set them in PCFieldSplitSetDefaults() */
21499566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc));
21509566063dSJacob Faibussowitsch     if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n"));
2151d32f9abdSBarry Smith   }
2152c5d2311dSJed Brown   if (jac->type == PC_COMPOSITE_SCHUR) {
21539566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetEnum(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_schur_factorization_type", PCFieldSplitSchurFactTypes, (PetscEnum *)&jac->schurfactorization, &flg));
21549566063dSJacob Faibussowitsch     if (flg) PetscCall(PetscInfo(pc, "Deprecated use of -pc_fieldsplit_schur_factorization_type\n"));
21559566063dSJacob 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));
21569566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_precondition", "How to build preconditioner for Schur complement", "PCFieldSplitSetSchurPre", PCFieldSplitSchurPreTypes, (PetscEnum)jac->schurpre, (PetscEnum *)&jac->schurpre, NULL));
21579566063dSJacob Faibussowitsch     PetscCall(PetscOptionsScalar("-pc_fieldsplit_schur_scale", "Scale Schur complement", "PCFieldSplitSetSchurScale", jac->schurscale, &jac->schurscale, NULL));
2158a51937d4SCarola Kruse   } else if (jac->type == PC_COMPOSITE_GKB) {
2159a077d33dSBarry Smith     PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_tol", "The tolerance for the lower bound stopping criterion", "PCFieldSplitSetGKBTol", jac->gkbtol, &jac->gkbtol, NULL));
2160a077d33dSBarry Smith     PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_delay", "The delay value for lower bound criterion", "PCFieldSplitSetGKBDelay", jac->gkbdelay, &jac->gkbdelay, NULL));
2161a077d33dSBarry Smith     PetscCall(PetscOptionsBoundedReal("-pc_fieldsplit_gkb_nu", "Parameter in augmented Lagrangian approach", "PCFieldSplitSetGKBNu", jac->gkbnu, &jac->gkbnu, NULL, 0.0));
2162a077d33dSBarry Smith     PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_maxit", "Maximum allowed number of iterations", "PCFieldSplitSetGKBMaxit", jac->gkbmaxit, &jac->gkbmaxit, NULL));
21639566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-pc_fieldsplit_gkb_monitor", "Prints number of GKB iterations and error", "PCFieldSplitGKB", jac->gkbmonitor, &jac->gkbmonitor, NULL));
2164c5d2311dSJed Brown   }
216534603f55SBarry Smith   /*
216634603f55SBarry Smith     In the initial call to this routine the sub-solver data structures do not exist so we cannot call KSPSetFromOptions() on them yet.
216734603f55SBarry 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
216834603f55SBarry Smith     is called on the outer solver in case changes were made in the options database
216934603f55SBarry Smith 
217034603f55SBarry 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()
217134603f55SBarry 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.
217234603f55SBarry Smith     Without this extra check test p2p1fetidp_olof_full and others fail with incorrect matrix types.
217334603f55SBarry Smith 
217434603f55SBarry Smith     There could be a negative side effect of calling the KSPSetFromOptions() below.
217534603f55SBarry Smith 
217634603f55SBarry 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
217734603f55SBarry Smith   */
217834603f55SBarry Smith   if (jac->issetup) {
217934603f55SBarry Smith     PC_FieldSplitLink ilink = jac->head;
218034603f55SBarry Smith     if (jac->type == PC_COMPOSITE_SCHUR) {
218134603f55SBarry Smith       if (jac->kspupper && jac->kspupper->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspupper));
218234603f55SBarry Smith       if (jac->kspschur && jac->kspschur->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspschur));
218334603f55SBarry Smith     }
218434603f55SBarry Smith     while (ilink) {
218534603f55SBarry Smith       if (ilink->ksp->totalits > 0) PetscCall(KSPSetFromOptions(ilink->ksp));
218634603f55SBarry Smith       ilink = ilink->next;
218734603f55SBarry Smith     }
218834603f55SBarry Smith   }
2189d0609cedSBarry Smith   PetscOptionsHeadEnd();
21903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21910971522cSBarry Smith }
21920971522cSBarry Smith 
2193d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col)
2194d71ae5a4SJacob Faibussowitsch {
219597bbdb24SBarry Smith   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
21965a9f2f41SSatish Balay   PC_FieldSplitLink ilink, next = jac->head;
219769a612a9SBarry Smith   char              prefix[128];
21985d4c12cdSJungho Lee   PetscInt          i;
2199835f2295SStefano Zampini   PetscLogEvent     nse;
22000971522cSBarry Smith 
22010971522cSBarry Smith   PetscFunctionBegin;
22026c924f48SJed Brown   if (jac->splitdefined) {
22039566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
22043ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
22056c924f48SJed Brown   }
2206ac530a7eSPierre 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]);
22079566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
2208a04f6461SBarry Smith   if (splitname) {
22099566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
2210a04f6461SBarry Smith   } else {
22119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(3, &ilink->splitname));
221263a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ilink->splitname, 2, "%" PetscInt_FMT, jac->nsplits));
2213a04f6461SBarry Smith   }
2214835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(jac->nsplits, &nse));
2215835f2295SStefano Zampini   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */
22169566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &ilink->fields));
22179566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ilink->fields, fields, n));
22189566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &ilink->fields_col));
22199566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ilink->fields_col, fields_col, n));
22202fa5cd67SKarl Rupp 
22215a9f2f41SSatish Balay   ilink->nfields = n;
22220298fd71SBarry Smith   ilink->next    = NULL;
22239566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
22243821be0aSBarry Smith   PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel));
22259566063dSJacob Faibussowitsch   PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
22269566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
22279566063dSJacob Faibussowitsch   PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
222869a612a9SBarry Smith 
22299566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
22309566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
22310971522cSBarry Smith 
22320971522cSBarry Smith   if (!next) {
22335a9f2f41SSatish Balay     jac->head       = ilink;
22340298fd71SBarry Smith     ilink->previous = NULL;
22350971522cSBarry Smith   } else {
2236ad540459SPierre Jolivet     while (next->next) next = next->next;
22375a9f2f41SSatish Balay     next->next      = ilink;
223851f519a2SBarry Smith     ilink->previous = next;
22390971522cSBarry Smith   }
22400971522cSBarry Smith   jac->nsplits++;
22413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22420971522cSBarry Smith }
22430971522cSBarry Smith 
2244d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp)
2245d71ae5a4SJacob Faibussowitsch {
2246285fb4e2SStefano Zampini   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2247285fb4e2SStefano Zampini 
2248285fb4e2SStefano Zampini   PetscFunctionBegin;
2249285fb4e2SStefano Zampini   *subksp = NULL;
2250285fb4e2SStefano Zampini   if (n) *n = 0;
2251285fb4e2SStefano Zampini   if (jac->type == PC_COMPOSITE_SCHUR) {
2252285fb4e2SStefano Zampini     PetscInt nn;
2253285fb4e2SStefano Zampini 
225428b400f6SJacob Faibussowitsch     PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()");
225563a3b9bcSJacob Faibussowitsch     PetscCheck(jac->nsplits == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unexpected number of splits %" PetscInt_FMT " != 2", jac->nsplits);
2256285fb4e2SStefano Zampini     nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0);
22579566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nn, subksp));
2258285fb4e2SStefano Zampini     (*subksp)[0] = jac->head->ksp;
2259285fb4e2SStefano Zampini     (*subksp)[1] = jac->kspschur;
2260285fb4e2SStefano Zampini     if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper;
2261285fb4e2SStefano Zampini     if (n) *n = nn;
2262285fb4e2SStefano Zampini   }
22633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2264285fb4e2SStefano Zampini }
2265285fb4e2SStefano Zampini 
2266d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc, PetscInt *n, KSP **subksp)
2267d71ae5a4SJacob Faibussowitsch {
2268e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2269e69d4d44SBarry Smith 
2270e69d4d44SBarry Smith   PetscFunctionBegin;
227128b400f6SJacob Faibussowitsch   PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()");
22729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(jac->nsplits, subksp));
22739566063dSJacob Faibussowitsch   PetscCall(MatSchurComplementGetKSP(jac->schur, *subksp));
22742fa5cd67SKarl Rupp 
2275e69d4d44SBarry Smith   (*subksp)[1] = jac->kspschur;
227613e0d083SBarry Smith   if (n) *n = jac->nsplits;
22773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2278e69d4d44SBarry Smith }
22790971522cSBarry Smith 
2280d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp)
2281d71ae5a4SJacob Faibussowitsch {
22820971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
22830971522cSBarry Smith   PetscInt          cnt   = 0;
22845a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
22850971522cSBarry Smith 
22860971522cSBarry Smith   PetscFunctionBegin;
22879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(jac->nsplits, subksp));
22885a9f2f41SSatish Balay   while (ilink) {
22895a9f2f41SSatish Balay     (*subksp)[cnt++] = ilink->ksp;
22905a9f2f41SSatish Balay     ilink            = ilink->next;
22910971522cSBarry Smith   }
229263a3b9bcSJacob 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);
229313e0d083SBarry Smith   if (n) *n = jac->nsplits;
22943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22950971522cSBarry Smith }
22960971522cSBarry Smith 
2297cc4c1da9SBarry Smith /*@
2298f1580f4eSBarry Smith   PCFieldSplitRestrictIS - Restricts the fieldsplit `IS`s to be within a given `IS`.
22996dbb499eSCian Wilson 
23006dbb499eSCian Wilson   Input Parameters:
23016dbb499eSCian Wilson + pc  - the preconditioner context
2302feefa0e1SJacob Faibussowitsch - isy - the index set that defines the indices to which the fieldsplit is to be restricted
23036dbb499eSCian Wilson 
23046dbb499eSCian Wilson   Level: advanced
23056dbb499eSCian Wilson 
2306feefa0e1SJacob Faibussowitsch   Developer Notes:
2307f1580f4eSBarry Smith   It seems the resulting `IS`s will not cover the entire space, so
2308f1580f4eSBarry Smith   how can they define a convergent preconditioner? Needs explaining.
2309f1580f4eSBarry Smith 
231060f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
23116dbb499eSCian Wilson @*/
2312d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitRestrictIS(PC pc, IS isy)
2313d71ae5a4SJacob Faibussowitsch {
23146dbb499eSCian Wilson   PetscFunctionBegin;
23156dbb499eSCian Wilson   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
23166dbb499eSCian Wilson   PetscValidHeaderSpecific(isy, IS_CLASSID, 2);
2317cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitRestrictIS_C", (PC, IS), (pc, isy));
23183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23196dbb499eSCian Wilson }
23206dbb499eSCian Wilson 
2321d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy)
2322d71ae5a4SJacob Faibussowitsch {
23236dbb499eSCian Wilson   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
23246dbb499eSCian Wilson   PC_FieldSplitLink ilink = jac->head, next;
23256dbb499eSCian Wilson   PetscInt          localsize, size, sizez, i;
23266dbb499eSCian Wilson   const PetscInt   *ind, *indz;
23276dbb499eSCian Wilson   PetscInt         *indc, *indcz;
23286dbb499eSCian Wilson   PetscBool         flg;
23296dbb499eSCian Wilson 
23306dbb499eSCian Wilson   PetscFunctionBegin;
23319566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isy, &localsize));
23329566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Scan(&localsize, &size, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)isy)));
23336dbb499eSCian Wilson   size -= localsize;
23346dbb499eSCian Wilson   while (ilink) {
23356dbb499eSCian Wilson     IS isrl, isr;
23361c7cfba8SBarry Smith     PC subpc;
23379566063dSJacob Faibussowitsch     PetscCall(ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl));
23389566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(isrl, &localsize));
23399566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(localsize, &indc));
23409566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrl, &ind));
23419566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(indc, ind, localsize));
23429566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrl, &ind));
23439566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&isrl));
23446dbb499eSCian Wilson     for (i = 0; i < localsize; i++) *(indc + i) += size;
23459566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)isy), localsize, indc, PETSC_OWN_POINTER, &isr));
23469566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isr));
23479566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is));
23486dbb499eSCian Wilson     ilink->is = isr;
23499566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isr));
23509566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is_col));
23516dbb499eSCian Wilson     ilink->is_col = isr;
23529566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&isr));
23539566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(ilink->ksp, &subpc));
23549566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)subpc, PCFIELDSPLIT, &flg));
23556dbb499eSCian Wilson     if (flg) {
23566dbb499eSCian Wilson       IS       iszl, isz;
23576dbb499eSCian Wilson       MPI_Comm comm;
23589566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ilink->is, &localsize));
23596dbb499eSCian Wilson       comm = PetscObjectComm((PetscObject)ilink->is);
23609566063dSJacob Faibussowitsch       PetscCall(ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl));
23619566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Scan(&localsize, &sizez, 1, MPIU_INT, MPI_SUM, comm));
23626dbb499eSCian Wilson       sizez -= localsize;
23639566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(iszl, &localsize));
23649566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localsize, &indcz));
23659566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iszl, &indz));
23669566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(indcz, indz, localsize));
23679566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iszl, &indz));
23689566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&iszl));
23696dbb499eSCian Wilson       for (i = 0; i < localsize; i++) *(indcz + i) += sizez;
23709566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, localsize, indcz, PETSC_OWN_POINTER, &isz));
23719566063dSJacob Faibussowitsch       PetscCall(PCFieldSplitRestrictIS(subpc, isz));
23729566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isz));
23736dbb499eSCian Wilson     }
23746dbb499eSCian Wilson     next  = ilink->next;
23756dbb499eSCian Wilson     ilink = next;
23766dbb499eSCian Wilson   }
23776dbb499eSCian Wilson   jac->isrestrict = PETSC_TRUE;
23783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23796dbb499eSCian Wilson }
23806dbb499eSCian Wilson 
2381d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc, const char splitname[], IS is)
2382d71ae5a4SJacob Faibussowitsch {
2383704ba839SBarry Smith   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
2384704ba839SBarry Smith   PC_FieldSplitLink ilink, next = jac->head;
2385704ba839SBarry Smith   char              prefix[128];
2386835f2295SStefano Zampini   PetscLogEvent     nse;
2387704ba839SBarry Smith 
2388704ba839SBarry Smith   PetscFunctionBegin;
23896c924f48SJed Brown   if (jac->splitdefined) {
23909566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
23913ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
23926c924f48SJed Brown   }
23939566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
2394a04f6461SBarry Smith   if (splitname) {
23959566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
2396a04f6461SBarry Smith   } else {
23979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(8, &ilink->splitname));
239863a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ilink->splitname, 7, "%" PetscInt_FMT, jac->nsplits));
2399a04f6461SBarry Smith   }
2400835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(jac->nsplits, &nse));
2401835f2295SStefano Zampini   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */
24029566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)is));
24039566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ilink->is));
2404b5787286SJed Brown   ilink->is = is;
24059566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)is));
24069566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ilink->is_col));
2407b5787286SJed Brown   ilink->is_col = is;
24080298fd71SBarry Smith   ilink->next   = NULL;
24099566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
24103821be0aSBarry Smith   PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel));
24119566063dSJacob Faibussowitsch   PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
24129566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
24139566063dSJacob Faibussowitsch   PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
2414704ba839SBarry Smith 
24159566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
24169566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
2417704ba839SBarry Smith 
2418704ba839SBarry Smith   if (!next) {
2419704ba839SBarry Smith     jac->head       = ilink;
24200298fd71SBarry Smith     ilink->previous = NULL;
2421704ba839SBarry Smith   } else {
2422ad540459SPierre Jolivet     while (next->next) next = next->next;
2423704ba839SBarry Smith     next->next      = ilink;
2424704ba839SBarry Smith     ilink->previous = next;
2425704ba839SBarry Smith   }
2426704ba839SBarry Smith   jac->nsplits++;
24273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2428704ba839SBarry Smith }
2429704ba839SBarry Smith 
24305d83a8b1SBarry Smith /*@
243160f59c3bSBarry Smith   PCFieldSplitSetFields - Sets the fields that define one particular split in `PCFIELDSPLIT`
24320971522cSBarry Smith 
2433c3339decSBarry Smith   Logically Collective
24340971522cSBarry Smith 
24350971522cSBarry Smith   Input Parameters:
24360971522cSBarry Smith + pc         - the preconditioner context
243760f59c3bSBarry Smith . splitname  - name of this split, if `NULL` the number of the split is used
24380971522cSBarry Smith . n          - the number of fields in this split
24393b374dbdSBarry Smith . fields     - the fields in this split
244080670ca5SBarry 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
244180670ca5SBarry Smith                of the matrix and `fields_col` provides the column indices for that block
244280670ca5SBarry Smith 
244380670ca5SBarry Smith   Options Database Key:
244480670ca5SBarry Smith . -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split
24450971522cSBarry Smith 
24460971522cSBarry Smith   Level: intermediate
24470971522cSBarry Smith 
244895452b02SPatrick Sanan   Notes:
2449f1580f4eSBarry Smith   Use `PCFieldSplitSetIS()` to set a  general set of indices as a split.
2450d32f9abdSBarry Smith 
245180670ca5SBarry Smith   If the matrix used to construct the preconditioner is `MATNEST` then field i refers to the `is_row[i]` `IS` passed to `MatCreateNest()`.
245280670ca5SBarry Smith 
245380670ca5SBarry Smith   If the matrix used to construct the preconditioner is not `MATNEST` then
245454c05997SPierre Jolivet   `PCFieldSplitSetFields()` is for defining fields as strided blocks (based on the block size provided to the matrix with `MatSetBlockSize()` or
245580670ca5SBarry Smith   to the `PC` with `PCFieldSplitSetBlockSize()`). For example, if the block
2456f1580f4eSBarry 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
245714c74629SNuno Nobre   0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x23x56x8.. x12x45x78x....
2458f1580f4eSBarry Smith   where the numbered entries indicate what is in the split.
2459d32f9abdSBarry Smith 
2460db4c96c1SJed Brown   This function is called once per split (it creates a new split each time).  Solve options
246160f59c3bSBarry Smith   for this split will be available under the prefix `-fieldsplit_SPLITNAME_`.
2462db4c96c1SJed Brown 
246380670ca5SBarry Smith   `PCFieldSplitSetIS()` does not support having a `fields_col` different from `fields`
24643b374dbdSBarry Smith 
2465feefa0e1SJacob Faibussowitsch   Developer Notes:
2466f1580f4eSBarry Smith   This routine does not actually create the `IS` representing the split, that is delayed
2467f1580f4eSBarry Smith   until `PCSetUp_FieldSplit()`, because information about the vector/matrix layouts may not be
24685d4c12cdSJungho Lee   available when this routine is called.
24695d4c12cdSJungho Lee 
247080670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetIS()`, `PCFieldSplitRestrictIS()`,
247154c05997SPierre Jolivet           `MatSetBlockSize()`, `MatCreateNest()`
24720971522cSBarry Smith @*/
2473cc4c1da9SBarry Smith PetscErrorCode PCFieldSplitSetFields(PC pc, const char splitname[], PetscInt n, const PetscInt fields[], const PetscInt fields_col[])
2474d71ae5a4SJacob Faibussowitsch {
24750971522cSBarry Smith   PetscFunctionBegin;
24760700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
24774f572ea9SToby Isaac   PetscAssertPointer(splitname, 2);
247863a3b9bcSJacob Faibussowitsch   PetscCheck(n >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, splitname);
24794f572ea9SToby Isaac   PetscAssertPointer(fields, 4);
2480cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetFields_C", (PC, const char[], PetscInt, const PetscInt *, const PetscInt *), (pc, splitname, n, fields, fields_col));
24813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
24820971522cSBarry Smith }
24830971522cSBarry Smith 
2484c84da90fSDmitry Karpeev /*@
2485f1580f4eSBarry Smith   PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build
2486c14e9f00SDavid Andrs   the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2487c84da90fSDmitry Karpeev 
2488c3339decSBarry Smith   Logically Collective
2489c84da90fSDmitry Karpeev 
2490c84da90fSDmitry Karpeev   Input Parameters:
2491c84da90fSDmitry Karpeev + pc  - the preconditioner object
2492c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
2493c84da90fSDmitry Karpeev 
249420f4b53cSBarry Smith   Options Database Key:
2495147403d9SBarry Smith . -pc_fieldsplit_diag_use_amat - use the Amat to provide the diagonal blocks
2496c84da90fSDmitry Karpeev 
2497c84da90fSDmitry Karpeev   Level: intermediate
2498c84da90fSDmitry Karpeev 
249960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetDiagUseAmat()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFIELDSPLIT`
2500c84da90fSDmitry Karpeev @*/
2501d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc, PetscBool flg)
2502d71ae5a4SJacob Faibussowitsch {
2503c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2504c84da90fSDmitry Karpeev   PetscBool      isfs;
2505c84da90fSDmitry Karpeev 
2506c84da90fSDmitry Karpeev   PetscFunctionBegin;
2507c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25089566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
250928b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2510c84da90fSDmitry Karpeev   jac->diag_use_amat = flg;
25113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2512c84da90fSDmitry Karpeev }
2513c84da90fSDmitry Karpeev 
2514c84da90fSDmitry Karpeev /*@
2515f1580f4eSBarry Smith   PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build
2516c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2517c84da90fSDmitry Karpeev 
2518c3339decSBarry Smith   Logically Collective
2519c84da90fSDmitry Karpeev 
252020f4b53cSBarry Smith   Input Parameter:
2521c84da90fSDmitry Karpeev . pc - the preconditioner object
2522c84da90fSDmitry Karpeev 
252320f4b53cSBarry Smith   Output Parameter:
2524c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
2525c84da90fSDmitry Karpeev 
2526c84da90fSDmitry Karpeev   Level: intermediate
2527c84da90fSDmitry Karpeev 
252860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetDiagUseAmat()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFIELDSPLIT`
2529c84da90fSDmitry Karpeev @*/
2530d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc, PetscBool *flg)
2531d71ae5a4SJacob Faibussowitsch {
2532c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2533c84da90fSDmitry Karpeev   PetscBool      isfs;
2534c84da90fSDmitry Karpeev 
2535c84da90fSDmitry Karpeev   PetscFunctionBegin;
2536c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25374f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
25389566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
253928b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2540c84da90fSDmitry Karpeev   *flg = jac->diag_use_amat;
25413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2542c84da90fSDmitry Karpeev }
2543c84da90fSDmitry Karpeev 
2544c84da90fSDmitry Karpeev /*@
2545f1580f4eSBarry Smith   PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build
2546c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2547c84da90fSDmitry Karpeev 
2548c3339decSBarry Smith   Logically Collective
2549c84da90fSDmitry Karpeev 
2550c84da90fSDmitry Karpeev   Input Parameters:
2551c84da90fSDmitry Karpeev + pc  - the preconditioner object
2552c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
2553c84da90fSDmitry Karpeev 
255420f4b53cSBarry Smith   Options Database Key:
2555147403d9SBarry Smith . -pc_fieldsplit_off_diag_use_amat <bool> - use the Amat to extract the off-diagonal blocks
2556c84da90fSDmitry Karpeev 
2557c84da90fSDmitry Karpeev   Level: intermediate
2558c84da90fSDmitry Karpeev 
255960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFieldSplitSetDiagUseAmat()`, `PCFIELDSPLIT`
2560c84da90fSDmitry Karpeev @*/
2561d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc, PetscBool flg)
2562d71ae5a4SJacob Faibussowitsch {
2563c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2564c84da90fSDmitry Karpeev   PetscBool      isfs;
2565c84da90fSDmitry Karpeev 
2566c84da90fSDmitry Karpeev   PetscFunctionBegin;
2567c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25689566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
256928b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2570c84da90fSDmitry Karpeev   jac->offdiag_use_amat = flg;
25713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2572c84da90fSDmitry Karpeev }
2573c84da90fSDmitry Karpeev 
2574c84da90fSDmitry Karpeev /*@
2575f1580f4eSBarry Smith   PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build
2576c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2577c84da90fSDmitry Karpeev 
2578c3339decSBarry Smith   Logically Collective
2579c84da90fSDmitry Karpeev 
258020f4b53cSBarry Smith   Input Parameter:
2581c84da90fSDmitry Karpeev . pc - the preconditioner object
2582c84da90fSDmitry Karpeev 
258320f4b53cSBarry Smith   Output Parameter:
2584c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
2585c84da90fSDmitry Karpeev 
2586c84da90fSDmitry Karpeev   Level: intermediate
2587c84da90fSDmitry Karpeev 
258860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFieldSplitGetDiagUseAmat()`, `PCFIELDSPLIT`
2589c84da90fSDmitry Karpeev @*/
2590d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc, PetscBool *flg)
2591d71ae5a4SJacob Faibussowitsch {
2592c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2593c84da90fSDmitry Karpeev   PetscBool      isfs;
2594c84da90fSDmitry Karpeev 
2595c84da90fSDmitry Karpeev   PetscFunctionBegin;
2596c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25974f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
25989566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
259928b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2600c84da90fSDmitry Karpeev   *flg = jac->offdiag_use_amat;
26013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2602c84da90fSDmitry Karpeev }
2603c84da90fSDmitry Karpeev 
2604cc4c1da9SBarry Smith /*@
2605f1580f4eSBarry Smith   PCFieldSplitSetIS - Sets the exact elements for a split in a `PCFIELDSPLIT`
2606704ba839SBarry Smith 
2607c3339decSBarry Smith   Logically Collective
2608704ba839SBarry Smith 
2609704ba839SBarry Smith   Input Parameters:
2610704ba839SBarry Smith + pc        - the preconditioner context
261160f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used
2612f1580f4eSBarry Smith - is        - the index set that defines the elements in this split
2613704ba839SBarry Smith 
261460f59c3bSBarry Smith   Level: intermediate
261560f59c3bSBarry Smith 
2616a6ffb8dbSJed Brown   Notes:
261780670ca5SBarry Smith   Use `PCFieldSplitSetFields()`, for splits defined by strided `IS` based on the matrix block size or the `is_rows[]` passed into `MATNEST`
2618a6ffb8dbSJed Brown 
2619db4c96c1SJed Brown   This function is called once per split (it creates a new split each time).  Solve options
2620db4c96c1SJed Brown   for this split will be available under the prefix -fieldsplit_SPLITNAME_.
2621d32f9abdSBarry Smith 
262280670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetFields()`
2623704ba839SBarry Smith @*/
2624d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetIS(PC pc, const char splitname[], IS is)
2625d71ae5a4SJacob Faibussowitsch {
2626704ba839SBarry Smith   PetscFunctionBegin;
26270700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26284f572ea9SToby Isaac   if (splitname) PetscAssertPointer(splitname, 2);
2629db4c96c1SJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
2630cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetIS_C", (PC, const char[], IS), (pc, splitname, is));
26313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2632704ba839SBarry Smith }
2633704ba839SBarry Smith 
2634cc4c1da9SBarry Smith /*@
2635f1580f4eSBarry Smith   PCFieldSplitGetIS - Retrieves the elements for a split as an `IS`
263657a9adfeSMatthew G Knepley 
2637c3339decSBarry Smith   Logically Collective
263857a9adfeSMatthew G Knepley 
263957a9adfeSMatthew G Knepley   Input Parameters:
264057a9adfeSMatthew G Knepley + pc        - the preconditioner context
264157a9adfeSMatthew G Knepley - splitname - name of this split
264257a9adfeSMatthew G Knepley 
264357a9adfeSMatthew G Knepley   Output Parameter:
2644feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split, or `NULL` if the split is not found
264557a9adfeSMatthew G Knepley 
264657a9adfeSMatthew G Knepley   Level: intermediate
264757a9adfeSMatthew G Knepley 
264880670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetIS()`, `PCFieldSplitGetISByIndex()`
264957a9adfeSMatthew G Knepley @*/
2650d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetIS(PC pc, const char splitname[], IS *is)
2651d71ae5a4SJacob Faibussowitsch {
265257a9adfeSMatthew G Knepley   PetscFunctionBegin;
265357a9adfeSMatthew G Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26544f572ea9SToby Isaac   PetscAssertPointer(splitname, 2);
26554f572ea9SToby Isaac   PetscAssertPointer(is, 3);
265657a9adfeSMatthew G Knepley   {
265757a9adfeSMatthew G Knepley     PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
265857a9adfeSMatthew G Knepley     PC_FieldSplitLink ilink = jac->head;
265957a9adfeSMatthew G Knepley     PetscBool         found;
266057a9adfeSMatthew G Knepley 
26610298fd71SBarry Smith     *is = NULL;
266257a9adfeSMatthew G Knepley     while (ilink) {
26639566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(ilink->splitname, splitname, &found));
266457a9adfeSMatthew G Knepley       if (found) {
266557a9adfeSMatthew G Knepley         *is = ilink->is;
266657a9adfeSMatthew G Knepley         break;
266757a9adfeSMatthew G Knepley       }
266857a9adfeSMatthew G Knepley       ilink = ilink->next;
266957a9adfeSMatthew G Knepley     }
267057a9adfeSMatthew G Knepley   }
26713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
267257a9adfeSMatthew G Knepley }
267357a9adfeSMatthew G Knepley 
2674cc4c1da9SBarry Smith /*@
2675f1580f4eSBarry Smith   PCFieldSplitGetISByIndex - Retrieves the elements for a given split as an `IS`
2676998f007dSPierre Jolivet 
2677c3339decSBarry Smith   Logically Collective
2678998f007dSPierre Jolivet 
2679998f007dSPierre Jolivet   Input Parameters:
2680998f007dSPierre Jolivet + pc    - the preconditioner context
2681998f007dSPierre Jolivet - index - index of this split
2682998f007dSPierre Jolivet 
2683998f007dSPierre Jolivet   Output Parameter:
2684feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split
2685998f007dSPierre Jolivet 
2686998f007dSPierre Jolivet   Level: intermediate
2687998f007dSPierre Jolivet 
268880670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitGetIS()`, `PCFieldSplitSetIS()`,
268980670ca5SBarry Smith 
2690998f007dSPierre Jolivet @*/
2691d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetISByIndex(PC pc, PetscInt index, IS *is)
2692d71ae5a4SJacob Faibussowitsch {
2693998f007dSPierre Jolivet   PetscFunctionBegin;
269463a3b9bcSJacob Faibussowitsch   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", index);
2695998f007dSPierre Jolivet   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26964f572ea9SToby Isaac   PetscAssertPointer(is, 3);
2697998f007dSPierre Jolivet   {
2698998f007dSPierre Jolivet     PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
2699998f007dSPierre Jolivet     PC_FieldSplitLink ilink = jac->head;
2700998f007dSPierre Jolivet     PetscInt          i     = 0;
270163a3b9bcSJacob Faibussowitsch     PetscCheck(index < jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", index, jac->nsplits);
2702998f007dSPierre Jolivet 
2703998f007dSPierre Jolivet     while (i < index) {
2704998f007dSPierre Jolivet       ilink = ilink->next;
2705998f007dSPierre Jolivet       ++i;
2706998f007dSPierre Jolivet     }
27079566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitGetIS(pc, ilink->splitname, is));
2708998f007dSPierre Jolivet   }
27093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2710998f007dSPierre Jolivet }
2711998f007dSPierre Jolivet 
271251f519a2SBarry Smith /*@
271351f519a2SBarry Smith   PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
271480670ca5SBarry Smith   fieldsplit preconditioner when calling `PCFieldSplitSetFields()`. If not set the matrix block size is used.
271551f519a2SBarry Smith 
2716c3339decSBarry Smith   Logically Collective
271751f519a2SBarry Smith 
271851f519a2SBarry Smith   Input Parameters:
271951f519a2SBarry Smith + pc - the preconditioner context
272051f519a2SBarry Smith - bs - the block size
272151f519a2SBarry Smith 
272251f519a2SBarry Smith   Level: intermediate
272351f519a2SBarry Smith 
272480670ca5SBarry Smith   Note:
272580670ca5SBarry Smith   If the matrix is a `MATNEST` then the `is_rows[]` passed to `MatCreateNest()` determines the fields.
272680670ca5SBarry Smith 
272760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
272851f519a2SBarry Smith @*/
2729d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetBlockSize(PC pc, PetscInt bs)
2730d71ae5a4SJacob Faibussowitsch {
273151f519a2SBarry Smith   PetscFunctionBegin;
27320700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2733c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, bs, 2);
2734cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetBlockSize_C", (PC, PetscInt), (pc, bs));
27353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
273651f519a2SBarry Smith }
273751f519a2SBarry Smith 
27380971522cSBarry Smith /*@C
2739f1580f4eSBarry Smith   PCFieldSplitGetSubKSP - Gets the `KSP` contexts for all splits
27400971522cSBarry Smith 
2741c3339decSBarry Smith   Collective
27420971522cSBarry Smith 
27430971522cSBarry Smith   Input Parameter:
27440971522cSBarry Smith . pc - the preconditioner context
27450971522cSBarry Smith 
27460971522cSBarry Smith   Output Parameters:
274713e0d083SBarry Smith + n      - the number of splits
2748f1580f4eSBarry Smith - subksp - the array of `KSP` contexts
2749196cc216SBarry Smith 
27500971522cSBarry Smith   Level: advanced
27510971522cSBarry Smith 
2752f1580f4eSBarry Smith   Notes:
2753f1580f4eSBarry Smith   After `PCFieldSplitGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()`
2754f1580f4eSBarry Smith   (not the `KSP`, just the array that contains them).
2755f1580f4eSBarry Smith 
2756f1580f4eSBarry Smith   You must call `PCSetUp()` before calling `PCFieldSplitGetSubKSP()`.
2757f1580f4eSBarry Smith 
2758f1580f4eSBarry Smith   If the fieldsplit is of type `PC_COMPOSITE_SCHUR`, it returns the `KSP` object used inside the
2759f1580f4eSBarry Smith   Schur complement and the `KSP` object used to iterate over the Schur complement.
2760f1580f4eSBarry Smith   To access all the `KSP` objects used in `PC_COMPOSITE_SCHUR`, use `PCFieldSplitSchurGetSubKSP()`.
2761f1580f4eSBarry Smith 
2762f1580f4eSBarry Smith   If the fieldsplit is of type `PC_COMPOSITE_GKB`, it returns the `KSP` object used to solve the
2763f1580f4eSBarry Smith   inner linear system defined by the matrix H in each loop.
2764f1580f4eSBarry Smith 
2765feaf08eaSBarry Smith   Fortran Note:
2766e41f517fSBarry Smith   Call `PCFieldSplitRestoreSubKSP()` when the array of `KSP` is no longer needed
2767f1580f4eSBarry Smith 
2768feefa0e1SJacob Faibussowitsch   Developer Notes:
2769f1580f4eSBarry Smith   There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()`
2770f1580f4eSBarry Smith 
277160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitSchurGetSubKSP()`
27720971522cSBarry Smith @*/
2773d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSubKSP(PC pc, PetscInt *n, KSP *subksp[])
2774d71ae5a4SJacob Faibussowitsch {
27750971522cSBarry Smith   PetscFunctionBegin;
27760700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
27774f572ea9SToby Isaac   if (n) PetscAssertPointer(n, 2);
2778cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
27793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
27800971522cSBarry Smith }
27810971522cSBarry Smith 
2782285fb4e2SStefano Zampini /*@C
2783f1580f4eSBarry Smith   PCFieldSplitSchurGetSubKSP - Gets the `KSP` contexts used inside the Schur complement based `PCFIELDSPLIT`
2784285fb4e2SStefano Zampini 
278560f59c3bSBarry Smith   Collective
2786285fb4e2SStefano Zampini 
2787285fb4e2SStefano Zampini   Input Parameter:
2788285fb4e2SStefano Zampini . pc - the preconditioner context
2789285fb4e2SStefano Zampini 
2790285fb4e2SStefano Zampini   Output Parameters:
2791285fb4e2SStefano Zampini + n      - the number of splits
2792f1580f4eSBarry Smith - subksp - the array of `KSP` contexts
2793285fb4e2SStefano Zampini 
2794285fb4e2SStefano Zampini   Level: advanced
2795285fb4e2SStefano Zampini 
2796f1580f4eSBarry Smith   Notes:
2797f1580f4eSBarry Smith   After `PCFieldSplitSchurGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()`
2798f1580f4eSBarry Smith   (not the `KSP` just the array that contains them).
2799f1580f4eSBarry Smith 
2800f1580f4eSBarry Smith   You must call `PCSetUp()` before calling `PCFieldSplitSchurGetSubKSP()`.
2801f1580f4eSBarry Smith 
2802f1580f4eSBarry Smith   If the fieldsplit type is of type `PC_COMPOSITE_SCHUR`, it returns (in order)
2803f1580f4eSBarry Smith +  1  - the `KSP` used for the (1,1) block
2804f1580f4eSBarry Smith .  2  - the `KSP` used for the Schur complement (not the one used for the interior Schur solver)
2805f1580f4eSBarry Smith -  3  - the `KSP` used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block).
2806f1580f4eSBarry Smith 
2807f1580f4eSBarry Smith   It returns a null array if the fieldsplit is not of type `PC_COMPOSITE_SCHUR`; in this case, you should use `PCFieldSplitGetSubKSP()`.
2808f1580f4eSBarry Smith 
2809feaf08eaSBarry Smith   Fortran Note:
2810e41f517fSBarry Smith   Call `PCFieldSplitSchurRestoreSubKSP()` when the array of `KSP` is no longer needed
2811f1580f4eSBarry Smith 
2812f1580f4eSBarry Smith   Developer Notes:
2813f1580f4eSBarry Smith   There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()`
2814f1580f4eSBarry Smith 
2815f1580f4eSBarry Smith   Should the functionality of `PCFieldSplitSchurGetSubKSP()` and `PCFieldSplitGetSubKSP()` be merged?
2816f1580f4eSBarry Smith 
281760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitGetSubKSP()`
2818285fb4e2SStefano Zampini @*/
2819d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc, PetscInt *n, KSP *subksp[])
2820d71ae5a4SJacob Faibussowitsch {
2821285fb4e2SStefano Zampini   PetscFunctionBegin;
2822285fb4e2SStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
28234f572ea9SToby Isaac   if (n) PetscAssertPointer(n, 2);
2824cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitSchurGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
28253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2826285fb4e2SStefano Zampini }
2827285fb4e2SStefano Zampini 
2828e69d4d44SBarry Smith /*@
2829c14e9f00SDavid Andrs   PCFieldSplitSetSchurPre -  Indicates from what operator the preconditioner is constructed for the Schur complement.
2830a1e3cbf9SBarry Smith   The default is the A11 matrix.
2831e69d4d44SBarry Smith 
2832c3339decSBarry Smith   Collective
2833e69d4d44SBarry Smith 
2834e69d4d44SBarry Smith   Input Parameters:
2835e69d4d44SBarry Smith + pc    - the preconditioner context
2836f1580f4eSBarry Smith . ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11` (default),
2837f1580f4eSBarry Smith               `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER`,
2838f1580f4eSBarry Smith               `PC_FIELDSPLIT_SCHUR_PRE_SELFP`, and `PC_FIELDSPLIT_SCHUR_PRE_FULL`
283960f59c3bSBarry Smith - pre   - matrix to use for preconditioning, or `NULL`
2840084e4875SJed Brown 
2841f1580f4eSBarry Smith   Options Database Keys:
2842d59693daSPierre Jolivet + -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`. See notes for meaning of various arguments
2843a1e3cbf9SBarry Smith - -fieldsplit_1_pc_type <pctype>                               - the preconditioner algorithm that is used to construct the preconditioner from the operator
2844e69d4d44SBarry Smith 
284560f59c3bSBarry Smith   Level: intermediate
284660f59c3bSBarry Smith 
2847fd1303e9SJungho Lee   Notes:
2848f1580f4eSBarry Smith   If ptype is
2849f1580f4eSBarry Smith +     a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner
2850f1580f4eSBarry Smith   matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix
2851f1580f4eSBarry Smith .     self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix:
2852e7593814SPierre Jolivet   The only preconditioners that currently work with this symbolic representation matrix object are `PCLSC` and `PCHPDDM`
2853f1580f4eSBarry Smith .     user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument
2854f1580f4eSBarry Smith   to this function).
2855a077d33dSBarry Smith .     selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation $ Sp = A11 - A10 inv(diag(A00)) A01 $
2856f1580f4eSBarry Smith   This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be
2857d59693daSPierre Jolivet   lumped before extracting the diagonal using the additional option `-fieldsplit_1_mat_schur_complement_ainv_type lump`
2858f1580f4eSBarry Smith -     full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation
2859f1580f4eSBarry Smith   computed internally by `PCFIELDSPLIT` (this is expensive)
2860f1580f4eSBarry Smith   useful mostly as a test that the Schur complement approach can work for your problem
2861fd1303e9SJungho Lee 
2862d59693daSPierre Jolivet   When solving a saddle point problem, where the A11 block is identically zero, using `a11` as the ptype only makes sense
2863a077d33dSBarry Smith   with the additional option `-fieldsplit_1_pc_type none`. Usually for saddle point problems one would use a `ptype` of `self` and
2864d59693daSPierre Jolivet   `-fieldsplit_1_pc_type lsc` which uses the least squares commutator to compute a preconditioner for the Schur complement.
2865fd1303e9SJungho Lee 
2866a077d33dSBarry Smith   Developer Note:
2867a077d33dSBarry Smith   The name of this function and the option `-pc_fieldsplit_schur_precondition` are inconsistent; precondition should be used everywhere.
2868feefa0e1SJacob Faibussowitsch 
2869a077d33dSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`,
2870a077d33dSBarry Smith           `MatSchurComplementSetAinvType()`, `PCLSC`, `PCFieldSplitSetSchurFactType()`
2871e69d4d44SBarry Smith @*/
2872d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurPre(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2873d71ae5a4SJacob Faibussowitsch {
2874e69d4d44SBarry Smith   PetscFunctionBegin;
28750700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2876cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurPre_C", (PC, PCFieldSplitSchurPreType, Mat), (pc, ptype, pre));
28773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2878e69d4d44SBarry Smith }
2879686bed4dSStefano Zampini 
2880d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurPrecondition(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2881d71ae5a4SJacob Faibussowitsch {
28829371c9d4SSatish Balay   return PCFieldSplitSetSchurPre(pc, ptype, pre);
28839371c9d4SSatish Balay } /* Deprecated name */
2884e69d4d44SBarry Smith 
288537a82bf0SJed Brown /*@
288637a82bf0SJed Brown   PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be
2887f1580f4eSBarry Smith   preconditioned.  See `PCFieldSplitSetSchurPre()` for details.
288837a82bf0SJed Brown 
2889c3339decSBarry Smith   Logically Collective
289037a82bf0SJed Brown 
2891f899ff85SJose E. Roman   Input Parameter:
289237a82bf0SJed Brown . pc - the preconditioner context
289337a82bf0SJed Brown 
289437a82bf0SJed Brown   Output Parameters:
2895d59693daSPierre 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`
2896d59693daSPierre Jolivet - pre   - matrix to use for preconditioning (with `PC_FIELDSPLIT_SCHUR_PRE_USER`), or `NULL`
289737a82bf0SJed Brown 
289837a82bf0SJed Brown   Level: intermediate
289937a82bf0SJed Brown 
2900d59693daSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCLSC`
290137a82bf0SJed Brown @*/
2902d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurPre(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre)
2903d71ae5a4SJacob Faibussowitsch {
290437a82bf0SJed Brown   PetscFunctionBegin;
290537a82bf0SJed Brown   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2906cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitGetSchurPre_C", (PC, PCFieldSplitSchurPreType *, Mat *), (pc, ptype, pre));
29073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2908e69d4d44SBarry Smith }
2909e69d4d44SBarry Smith 
291045e7fc46SDmitry Karpeev /*@
2911f1580f4eSBarry Smith   PCFieldSplitSchurGetS -  extract the `MATSCHURCOMPLEMENT` object used by this `PCFIELDSPLIT` in case it needs to be configured separately
291245e7fc46SDmitry Karpeev 
291320f4b53cSBarry Smith   Not Collective
291445e7fc46SDmitry Karpeev 
291545e7fc46SDmitry Karpeev   Input Parameter:
291645e7fc46SDmitry Karpeev . pc - the preconditioner context
291745e7fc46SDmitry Karpeev 
291845e7fc46SDmitry Karpeev   Output Parameter:
2919470b340bSDmitry Karpeev . S - the Schur complement matrix
292045e7fc46SDmitry Karpeev 
292160f59c3bSBarry Smith   Level: advanced
292260f59c3bSBarry Smith 
2923f1580f4eSBarry Smith   Note:
2924f1580f4eSBarry Smith   This matrix should not be destroyed using `MatDestroy()`; rather, use `PCFieldSplitSchurRestoreS()`.
292545e7fc46SDmitry Karpeev 
292660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MATSCHURCOMPLEMENT`, `PCFieldSplitSchurRestoreS()`,
2927f1580f4eSBarry Smith           `MatCreateSchurComplement()`, `MatSchurComplementGetKSP()`, `MatSchurComplementComputeExplicitOperator()`, `MatGetSchurComplement()`
292845e7fc46SDmitry Karpeev @*/
2929d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetS(PC pc, Mat *S)
2930d71ae5a4SJacob Faibussowitsch {
293145e7fc46SDmitry Karpeev   const char    *t;
293245e7fc46SDmitry Karpeev   PetscBool      isfs;
293345e7fc46SDmitry Karpeev   PC_FieldSplit *jac;
293445e7fc46SDmitry Karpeev 
293545e7fc46SDmitry Karpeev   PetscFunctionBegin;
293645e7fc46SDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
29379566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetType((PetscObject)pc, &t));
29389566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
293928b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
294045e7fc46SDmitry Karpeev   jac = (PC_FieldSplit *)pc->data;
294163a3b9bcSJacob Faibussowitsch   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
2942470b340bSDmitry Karpeev   if (S) *S = jac->schur;
29433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
294445e7fc46SDmitry Karpeev }
294545e7fc46SDmitry Karpeev 
2946470b340bSDmitry Karpeev /*@
2947f1580f4eSBarry Smith   PCFieldSplitSchurRestoreS -  returns the `MATSCHURCOMPLEMENT` matrix used by this `PC`
2948470b340bSDmitry Karpeev 
294920f4b53cSBarry Smith   Not Collective
2950470b340bSDmitry Karpeev 
2951470b340bSDmitry Karpeev   Input Parameters:
2952470b340bSDmitry Karpeev + pc - the preconditioner context
2953a2b725a8SWilliam Gropp - S  - the Schur complement matrix
2954470b340bSDmitry Karpeev 
2955470b340bSDmitry Karpeev   Level: advanced
2956470b340bSDmitry Karpeev 
295760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurGetS()`
2958470b340bSDmitry Karpeev @*/
2959d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurRestoreS(PC pc, Mat *S)
2960d71ae5a4SJacob Faibussowitsch {
2961470b340bSDmitry Karpeev   const char    *t;
2962470b340bSDmitry Karpeev   PetscBool      isfs;
2963470b340bSDmitry Karpeev   PC_FieldSplit *jac;
2964470b340bSDmitry Karpeev 
2965470b340bSDmitry Karpeev   PetscFunctionBegin;
2966470b340bSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
29679566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetType((PetscObject)pc, &t));
29689566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
296928b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
2970470b340bSDmitry Karpeev   jac = (PC_FieldSplit *)pc->data;
297163a3b9bcSJacob Faibussowitsch   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
29727827d75bSBarry Smith   PetscCheck(S && (*S == jac->schur), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatSchurComplement restored is not the same as gotten");
29733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2974470b340bSDmitry Karpeev }
2975470b340bSDmitry Karpeev 
2976d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2977d71ae5a4SJacob Faibussowitsch {
2978e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2979e69d4d44SBarry Smith 
2980e69d4d44SBarry Smith   PetscFunctionBegin;
2981084e4875SJed Brown   jac->schurpre = ptype;
2982a7476a74SDmitry Karpeev   if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) {
29839566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&jac->schur_user));
2984084e4875SJed Brown     jac->schur_user = pre;
29859566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)jac->schur_user));
2986084e4875SJed Brown   }
29873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2988e69d4d44SBarry Smith }
2989e69d4d44SBarry Smith 
2990d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre)
2991d71ae5a4SJacob Faibussowitsch {
299237a82bf0SJed Brown   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
299337a82bf0SJed Brown 
299437a82bf0SJed Brown   PetscFunctionBegin;
29956056e507SPierre Jolivet   if (ptype) *ptype = jac->schurpre;
29966056e507SPierre Jolivet   if (pre) *pre = jac->schur_user;
29973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
299837a82bf0SJed Brown }
299937a82bf0SJed Brown 
3000ab1df9f5SJed Brown /*@
30011d27aa22SBarry Smith   PCFieldSplitSetSchurFactType -  sets which blocks of the approximate block factorization to retain in the preconditioner {cite}`murphy2000note` and {cite}`ipsen2001note`
3002ab1df9f5SJed Brown 
3003c3339decSBarry Smith   Collective
3004ab1df9f5SJed Brown 
3005ab1df9f5SJed Brown   Input Parameters:
3006ab1df9f5SJed Brown + pc    - the preconditioner context
3007f1580f4eSBarry Smith - ftype - which blocks of factorization to retain, `PC_FIELDSPLIT_SCHUR_FACT_FULL` is default
3008ab1df9f5SJed Brown 
3009f1580f4eSBarry Smith   Options Database Key:
3010d59693daSPierre Jolivet . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - default is `full`
3011ab1df9f5SJed Brown 
3012ab1df9f5SJed Brown   Level: intermediate
3013ab1df9f5SJed Brown 
3014ab1df9f5SJed Brown   Notes:
3015366f9a6aSPierre Jolivet   The `full` factorization is
3016ab1df9f5SJed Brown 
3017a077d33dSBarry Smith   ```{math}
3018a077d33dSBarry Smith   \left(\begin{array}{cc} A & B \\
3019a077d33dSBarry Smith   C & E \\
3020a077d33dSBarry Smith   \end{array}\right) =
3021366f9a6aSPierre Jolivet   \left(\begin{array}{cc} I & 0 \\
3022366f9a6aSPierre Jolivet   C A^{-1} & I \\
3023a077d33dSBarry Smith   \end{array}\right)
3024a077d33dSBarry Smith   \left(\begin{array}{cc} A & 0 \\
3025a077d33dSBarry Smith   0 & S \\
3026a077d33dSBarry Smith   \end{array}\right)
3027a077d33dSBarry Smith   \left(\begin{array}{cc} I & A^{-1}B \\
3028a077d33dSBarry Smith   0 & I \\
3029366f9a6aSPierre Jolivet   \end{array}\right) = L D U,
3030a077d33dSBarry Smith   ```
3031a077d33dSBarry Smith 
3032366f9a6aSPierre 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$,
3033366f9a6aSPierre Jolivet   and `diag` is the diagonal part with the sign of $S$ flipped (because this makes the preconditioner positive definite for many formulations,
3034a077d33dSBarry Smith   thus allowing the use of `KSPMINRES)`. Sign flipping of $S$ can be turned off with `PCFieldSplitSetSchurScale()`.
3035a077d33dSBarry Smith 
3036a077d33dSBarry Smith   If $A$ and $S$ are solved exactly
3037366f9a6aSPierre Jolivet +  1 - `full` factorization is a direct solver.
3038366f9a6aSPierre 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.
3039366f9a6aSPierre 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.
3040ab1df9f5SJed Brown 
3041f1580f4eSBarry Smith   If the iteration count is very low, consider using `KSPFGMRES` or `KSPGCR` which can use one less preconditioner
30420ffb0e17SBarry 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.
30430ffb0e17SBarry Smith 
3044366f9a6aSPierre Jolivet   For symmetric problems in which $A$ is positive definite and $S$ is negative definite, `diag` can be used with `KSPMINRES`.
30450ffb0e17SBarry Smith 
3046366f9a6aSPierre 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$).
3047ab1df9f5SJed Brown 
30481d27aa22SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurScale()`,
3049a077d33dSBarry Smith           [](sec_flexibleksp), `PCFieldSplitSetSchurPre()`
3050ab1df9f5SJed Brown @*/
3051d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurFactType(PC pc, PCFieldSplitSchurFactType ftype)
3052d71ae5a4SJacob Faibussowitsch {
3053ab1df9f5SJed Brown   PetscFunctionBegin;
3054ab1df9f5SJed Brown   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3055cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurFactType_C", (PC, PCFieldSplitSchurFactType), (pc, ftype));
30563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3057ab1df9f5SJed Brown }
3058ab1df9f5SJed Brown 
3059d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc, PCFieldSplitSchurFactType ftype)
3060d71ae5a4SJacob Faibussowitsch {
3061ab1df9f5SJed Brown   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3062ab1df9f5SJed Brown 
3063ab1df9f5SJed Brown   PetscFunctionBegin;
3064ab1df9f5SJed Brown   jac->schurfactorization = ftype;
30653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3066ab1df9f5SJed Brown }
3067ab1df9f5SJed Brown 
3068c096484dSStefano Zampini /*@
3069f1580f4eSBarry Smith   PCFieldSplitSetSchurScale -  Controls the sign flip of S for `PC_FIELDSPLIT_SCHUR_FACT_DIAG`.
3070c096484dSStefano Zampini 
3071c3339decSBarry Smith   Collective
3072c096484dSStefano Zampini 
3073c096484dSStefano Zampini   Input Parameters:
3074c096484dSStefano Zampini + pc    - the preconditioner context
3075c096484dSStefano Zampini - scale - scaling factor for the Schur complement
3076c096484dSStefano Zampini 
3077f1580f4eSBarry Smith   Options Database Key:
30781d27aa22SBarry Smith . -pc_fieldsplit_schur_scale <scale> - default is -1.0
3079c096484dSStefano Zampini 
3080c096484dSStefano Zampini   Level: intermediate
3081c096484dSStefano Zampini 
308242747ad1SJacob Faibussowitsch .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurFactType`, `PCFieldSplitSetSchurFactType()`
3083c096484dSStefano Zampini @*/
3084d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurScale(PC pc, PetscScalar scale)
3085d71ae5a4SJacob Faibussowitsch {
3086c096484dSStefano Zampini   PetscFunctionBegin;
3087c096484dSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3088c096484dSStefano Zampini   PetscValidLogicalCollectiveScalar(pc, scale, 2);
3089cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurScale_C", (PC, PetscScalar), (pc, scale));
30903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3091c096484dSStefano Zampini }
3092c096484dSStefano Zampini 
3093d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc, PetscScalar scale)
3094d71ae5a4SJacob Faibussowitsch {
3095c096484dSStefano Zampini   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3096c096484dSStefano Zampini 
3097c096484dSStefano Zampini   PetscFunctionBegin;
3098c096484dSStefano Zampini   jac->schurscale = scale;
30993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3100c096484dSStefano Zampini }
3101c096484dSStefano Zampini 
310230ad9308SMatthew Knepley /*@C
31038c03b21aSDmitry Karpeev   PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
310430ad9308SMatthew Knepley 
3105c3339decSBarry Smith   Collective
310630ad9308SMatthew Knepley 
310730ad9308SMatthew Knepley   Input Parameter:
310830ad9308SMatthew Knepley . pc - the preconditioner context
310930ad9308SMatthew Knepley 
311030ad9308SMatthew Knepley   Output Parameters:
3111a04f6461SBarry Smith + A00 - the (0,0) block
3112a04f6461SBarry Smith . A01 - the (0,1) block
3113a04f6461SBarry Smith . A10 - the (1,0) block
3114a04f6461SBarry Smith - A11 - the (1,1) block
311530ad9308SMatthew Knepley 
311630ad9308SMatthew Knepley   Level: advanced
311730ad9308SMatthew Knepley 
31185d83a8b1SBarry Smith   Note:
31195d83a8b1SBarry Smith   Use `NULL` for any unneeded output arguments
31205d83a8b1SBarry Smith 
312160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `MatSchurComplementGetSubMatrices()`, `MatSchurComplementSetSubMatrices()`
312230ad9308SMatthew Knepley @*/
3123d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc, Mat *A00, Mat *A01, Mat *A10, Mat *A11)
3124d71ae5a4SJacob Faibussowitsch {
312530ad9308SMatthew Knepley   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
312630ad9308SMatthew Knepley 
312730ad9308SMatthew Knepley   PetscFunctionBegin;
31280700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
312908401ef6SPierre Jolivet   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
3130a04f6461SBarry Smith   if (A00) *A00 = jac->pmat[0];
3131a04f6461SBarry Smith   if (A01) *A01 = jac->B;
3132a04f6461SBarry Smith   if (A10) *A10 = jac->C;
3133a04f6461SBarry Smith   if (A11) *A11 = jac->pmat[1];
31343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
313530ad9308SMatthew Knepley }
313630ad9308SMatthew Knepley 
3137b09e027eSCarola Kruse /*@
31381d27aa22SBarry Smith   PCFieldSplitSetGKBTol -  Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3139b09e027eSCarola Kruse 
3140c3339decSBarry Smith   Collective
3141e071a0a4SCarola Kruse 
3142b09e027eSCarola Kruse   Input Parameters:
3143b09e027eSCarola Kruse + pc        - the preconditioner context
3144b09e027eSCarola Kruse - tolerance - the solver tolerance
3145b09e027eSCarola Kruse 
3146f1580f4eSBarry Smith   Options Database Key:
31471d27aa22SBarry Smith . -pc_fieldsplit_gkb_tol <tolerance> - default is 1e-5
3148b09e027eSCarola Kruse 
3149b09e027eSCarola Kruse   Level: intermediate
3150b09e027eSCarola Kruse 
3151f1580f4eSBarry Smith   Note:
31521d27aa22SBarry Smith   The generalized GKB algorithm {cite}`arioli2013` uses a lower bound estimate of the error in energy norm as stopping criterion.
3153f1580f4eSBarry Smith   It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than
31541d27aa22SBarry Smith   this estimate, the stopping criterion is satisfactory in practical cases.
3155f1580f4eSBarry Smith 
315660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBMaxit()`
3157b09e027eSCarola Kruse @*/
3158d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBTol(PC pc, PetscReal tolerance)
3159d71ae5a4SJacob Faibussowitsch {
3160b09e027eSCarola Kruse   PetscFunctionBegin;
3161b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3162de482cd7SCarola Kruse   PetscValidLogicalCollectiveReal(pc, tolerance, 2);
3163cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBTol_C", (PC, PetscReal), (pc, tolerance));
31643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3165b09e027eSCarola Kruse }
3166b09e027eSCarola Kruse 
3167d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc, PetscReal tolerance)
3168d71ae5a4SJacob Faibussowitsch {
3169b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3170b09e027eSCarola Kruse 
3171b09e027eSCarola Kruse   PetscFunctionBegin;
3172b09e027eSCarola Kruse   jac->gkbtol = tolerance;
31733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3174b09e027eSCarola Kruse }
3175b09e027eSCarola Kruse 
3176b09e027eSCarola Kruse /*@
317780670ca5SBarry Smith   PCFieldSplitSetGKBMaxit -  Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3178b09e027eSCarola Kruse 
3179c3339decSBarry Smith   Collective
3180b09e027eSCarola Kruse 
3181b09e027eSCarola Kruse   Input Parameters:
3182b09e027eSCarola Kruse + pc    - the preconditioner context
3183b09e027eSCarola Kruse - maxit - the maximum number of iterations
3184b09e027eSCarola Kruse 
3185f1580f4eSBarry Smith   Options Database Key:
31861d27aa22SBarry Smith . -pc_fieldsplit_gkb_maxit <maxit> - default is 100
3187b09e027eSCarola Kruse 
3188b09e027eSCarola Kruse   Level: intermediate
3189b09e027eSCarola Kruse 
319060f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBNu()`
3191b09e027eSCarola Kruse @*/
3192d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc, PetscInt maxit)
3193d71ae5a4SJacob Faibussowitsch {
3194b09e027eSCarola Kruse   PetscFunctionBegin;
3195b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3196de482cd7SCarola Kruse   PetscValidLogicalCollectiveInt(pc, maxit, 2);
3197cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBMaxit_C", (PC, PetscInt), (pc, maxit));
31983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3199b09e027eSCarola Kruse }
3200b09e027eSCarola Kruse 
3201d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc, PetscInt maxit)
3202d71ae5a4SJacob Faibussowitsch {
3203b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3204b09e027eSCarola Kruse 
3205b09e027eSCarola Kruse   PetscFunctionBegin;
3206b09e027eSCarola Kruse   jac->gkbmaxit = maxit;
32073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3208b09e027eSCarola Kruse }
3209b09e027eSCarola Kruse 
3210b09e027eSCarola Kruse /*@
32111d27aa22SBarry Smith   PCFieldSplitSetGKBDelay -  Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization {cite}`arioli2013` in `PCFIELDSPLIT`
3212e071a0a4SCarola Kruse   preconditioner.
3213b09e027eSCarola Kruse 
3214c3339decSBarry Smith   Collective
3215b09e027eSCarola Kruse 
3216b09e027eSCarola Kruse   Input Parameters:
3217b09e027eSCarola Kruse + pc    - the preconditioner context
3218b09e027eSCarola Kruse - delay - the delay window in the lower bound estimate
3219b09e027eSCarola Kruse 
3220f1580f4eSBarry Smith   Options Database Key:
32211d27aa22SBarry Smith . -pc_fieldsplit_gkb_delay <delay> - default is 5
3222b09e027eSCarola Kruse 
3223b09e027eSCarola Kruse   Level: intermediate
3224b09e027eSCarola Kruse 
32251d27aa22SBarry Smith   Notes:
32261d27aa22SBarry 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 $
32271d27aa22SBarry 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
32281d27aa22SBarry Smith   at least (`delay` + 1) iterations to stop.
3229f1580f4eSBarry Smith 
32301d27aa22SBarry Smith   For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to {cite}`arioli2013`
3231f1580f4eSBarry Smith 
323260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
3233b09e027eSCarola Kruse @*/
3234d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBDelay(PC pc, PetscInt delay)
3235d71ae5a4SJacob Faibussowitsch {
3236b09e027eSCarola Kruse   PetscFunctionBegin;
3237b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3238b09e027eSCarola Kruse   PetscValidLogicalCollectiveInt(pc, delay, 2);
3239cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBDelay_C", (PC, PetscInt), (pc, delay));
32403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3241b09e027eSCarola Kruse }
3242b09e027eSCarola Kruse 
3243d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc, PetscInt delay)
3244d71ae5a4SJacob Faibussowitsch {
3245b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3246b09e027eSCarola Kruse 
3247b09e027eSCarola Kruse   PetscFunctionBegin;
3248b09e027eSCarola Kruse   jac->gkbdelay = delay;
32493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3250b09e027eSCarola Kruse }
3251b09e027eSCarola Kruse 
3252b09e027eSCarola Kruse /*@
32531d27aa22SBarry Smith   PCFieldSplitSetGKBNu -  Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the
32541d27aa22SBarry Smith   Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3255b09e027eSCarola Kruse 
3256c3339decSBarry Smith   Collective
3257f1580f4eSBarry Smith 
3258f1580f4eSBarry Smith   Input Parameters:
3259f1580f4eSBarry Smith + pc - the preconditioner context
3260f1580f4eSBarry Smith - nu - the shift parameter
3261f1580f4eSBarry Smith 
326220f4b53cSBarry Smith   Options Database Key:
32631d27aa22SBarry Smith . -pc_fieldsplit_gkb_nu <nu> - default is 1
3264f1580f4eSBarry Smith 
3265f1580f4eSBarry Smith   Level: intermediate
3266b09e027eSCarola Kruse 
3267b09e027eSCarola Kruse   Notes:
32681d27aa22SBarry 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,
32691d27aa22SBarry 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
3270b09e027eSCarola Kruse   necessary to find a good balance in between the convergence of the inner and outer loop.
3271b09e027eSCarola Kruse 
32721d27aa22SBarry 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.
3273b09e027eSCarola Kruse 
327460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
3275b09e027eSCarola Kruse @*/
3276d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBNu(PC pc, PetscReal nu)
3277d71ae5a4SJacob Faibussowitsch {
3278b09e027eSCarola Kruse   PetscFunctionBegin;
3279b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3280de482cd7SCarola Kruse   PetscValidLogicalCollectiveReal(pc, nu, 2);
3281cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBNu_C", (PC, PetscReal), (pc, nu));
32823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3283b09e027eSCarola Kruse }
3284b09e027eSCarola Kruse 
3285d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc, PetscReal nu)
3286d71ae5a4SJacob Faibussowitsch {
3287b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3288b09e027eSCarola Kruse 
3289b09e027eSCarola Kruse   PetscFunctionBegin;
3290b09e027eSCarola Kruse   jac->gkbnu = nu;
32913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3292b09e027eSCarola Kruse }
3293b09e027eSCarola Kruse 
3294d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc, PCCompositeType type)
3295d71ae5a4SJacob Faibussowitsch {
329679416396SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
329779416396SBarry Smith 
329879416396SBarry Smith   PetscFunctionBegin;
329979416396SBarry Smith   jac->type = type;
33002e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
33012e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
33022e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
33032e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
33042e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
33052e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
33062e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
33072e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
33082e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
3309e071a0a4SCarola Kruse 
33103b224e63SBarry Smith   if (type == PC_COMPOSITE_SCHUR) {
33113b224e63SBarry Smith     pc->ops->apply          = PCApply_FieldSplit_Schur;
33127b665727SPierre Jolivet     pc->ops->applytranspose = PCApplyTranspose_FieldSplit_Schur;
3313*f5b94327SPierre Jolivet     pc->ops->matapply       = PCMatApply_FieldSplit_Schur;
33143b224e63SBarry Smith     pc->ops->view           = PCView_FieldSplit_Schur;
331573716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit_Schur;
33162fa5cd67SKarl Rupp 
33179566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit_Schur));
33189566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", PCFieldSplitSetSchurPre_FieldSplit));
33199566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", PCFieldSplitGetSchurPre_FieldSplit));
33209566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", PCFieldSplitSetSchurFactType_FieldSplit));
33219566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", PCFieldSplitSetSchurScale_FieldSplit));
3322a51937d4SCarola Kruse   } else if (type == PC_COMPOSITE_GKB) {
3323a51937d4SCarola Kruse     pc->ops->apply          = PCApply_FieldSplit_GKB;
33247ff38633SStefano Zampini     pc->ops->applytranspose = NULL;
3325d484b384SBoris Martin     pc->ops->matapply       = NULL;
3326a51937d4SCarola Kruse     pc->ops->view           = PCView_FieldSplit_GKB;
332773716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit_GKB;
3328e69d4d44SBarry Smith 
33299566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
33309566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", PCFieldSplitSetGKBTol_FieldSplit));
33319566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", PCFieldSplitSetGKBMaxit_FieldSplit));
33329566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", PCFieldSplitSetGKBNu_FieldSplit));
33339566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", PCFieldSplitSetGKBDelay_FieldSplit));
33343b224e63SBarry Smith   } else {
33353b224e63SBarry Smith     pc->ops->apply          = PCApply_FieldSplit;
33367ff38633SStefano Zampini     pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
3337d484b384SBoris Martin     pc->ops->matapply       = PCMatApply_FieldSplit;
33383b224e63SBarry Smith     pc->ops->view           = PCView_FieldSplit;
333973716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit;
33402fa5cd67SKarl Rupp 
33419566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
33423b224e63SBarry Smith   }
33433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
334479416396SBarry Smith }
334579416396SBarry Smith 
3346d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc, PetscInt bs)
3347d71ae5a4SJacob Faibussowitsch {
334851f519a2SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
334951f519a2SBarry Smith 
335051f519a2SBarry Smith   PetscFunctionBegin;
335163a3b9bcSJacob Faibussowitsch   PetscCheck(bs >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs);
33522472a847SBarry 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);
335351f519a2SBarry Smith   jac->bs = bs;
33543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
335551f519a2SBarry Smith }
335651f519a2SBarry Smith 
3357d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[])
3358d71ae5a4SJacob Faibussowitsch {
33595ddf11f8SNicolas Barnafi   PC_FieldSplit    *jac           = (PC_FieldSplit *)pc->data;
33605ddf11f8SNicolas Barnafi   PC_FieldSplitLink ilink_current = jac->head;
33615ddf11f8SNicolas Barnafi   IS                is_owned;
33625ddf11f8SNicolas Barnafi 
33635ddf11f8SNicolas Barnafi   PetscFunctionBegin;
33645ddf11f8SNicolas Barnafi   jac->coordinates_set = PETSC_TRUE; // Internal flag
3365f3fa974cSJacob Faibussowitsch   PetscCall(MatGetOwnershipIS(pc->mat, &is_owned, NULL));
33665ddf11f8SNicolas Barnafi 
33675ddf11f8SNicolas Barnafi   while (ilink_current) {
33685ddf11f8SNicolas Barnafi     // For each IS, embed it to get local coords indces
33695ddf11f8SNicolas Barnafi     IS              is_coords;
33705ddf11f8SNicolas Barnafi     PetscInt        ndofs_block;
33715ddf11f8SNicolas Barnafi     const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block
33725ddf11f8SNicolas Barnafi 
33735ddf11f8SNicolas Barnafi     // Setting drop to true for safety. It should make no difference.
33749566063dSJacob Faibussowitsch     PetscCall(ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords));
33759566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is_coords, &ndofs_block));
33769566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is_coords, &block_dofs_enumeration));
33775ddf11f8SNicolas Barnafi 
33785ddf11f8SNicolas Barnafi     // Allocate coordinates vector and set it directly
3379f4f49eeaSPierre Jolivet     PetscCall(PetscMalloc1(ndofs_block * dim, &ilink_current->coords));
33805ddf11f8SNicolas Barnafi     for (PetscInt dof = 0; dof < ndofs_block; ++dof) {
3381ad540459SPierre Jolivet       for (PetscInt d = 0; d < dim; ++d) (ilink_current->coords)[dim * dof + d] = coords[dim * block_dofs_enumeration[dof] + d];
33825ddf11f8SNicolas Barnafi     }
33835ddf11f8SNicolas Barnafi     ilink_current->dim   = dim;
33845ddf11f8SNicolas Barnafi     ilink_current->ndofs = ndofs_block;
33859566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is_coords, &block_dofs_enumeration));
33869566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_coords));
33875ddf11f8SNicolas Barnafi     ilink_current = ilink_current->next;
33885ddf11f8SNicolas Barnafi   }
33899566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_owned));
33903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33915ddf11f8SNicolas Barnafi }
33925ddf11f8SNicolas Barnafi 
3393bc08b0f1SBarry Smith /*@
3394f1580f4eSBarry Smith   PCFieldSplitSetType - Sets the type, `PCCompositeType`, of a `PCFIELDSPLIT`
339579416396SBarry Smith 
3396c3339decSBarry Smith   Collective
339779416396SBarry Smith 
3398d8d19677SJose E. Roman   Input Parameters:
3399a2b725a8SWilliam Gropp + pc   - the preconditioner context
3400a077d33dSBarry Smith - type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`,
3401a077d33dSBarry Smith          `PC_COMPOSITE_GKB`
340279416396SBarry Smith 
340379416396SBarry Smith   Options Database Key:
34041d27aa22SBarry Smith . -pc_fieldsplit_type <one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
340579416396SBarry Smith 
3406feefa0e1SJacob Faibussowitsch   Level: intermediate
340779416396SBarry Smith 
340860f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCCompositeType`, `PCCompositeGetType()`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`,
3409a077d33dSBarry Smith           `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`, `PCFieldSplitSetSchurFactType()`
341079416396SBarry Smith @*/
3411d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetType(PC pc, PCCompositeType type)
3412d71ae5a4SJacob Faibussowitsch {
341379416396SBarry Smith   PetscFunctionBegin;
34140700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3415cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetType_C", (PC, PCCompositeType), (pc, type));
34163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
341779416396SBarry Smith }
341879416396SBarry Smith 
3419b02e2d75SMatthew G Knepley /*@
3420f1580f4eSBarry Smith   PCFieldSplitGetType - Gets the type, `PCCompositeType`, of a `PCFIELDSPLIT`
3421b02e2d75SMatthew G Knepley 
3422b02e2d75SMatthew G Knepley   Not collective
3423b02e2d75SMatthew G Knepley 
3424b02e2d75SMatthew G Knepley   Input Parameter:
3425b02e2d75SMatthew G Knepley . pc - the preconditioner context
3426b02e2d75SMatthew G Knepley 
3427b02e2d75SMatthew G Knepley   Output Parameter:
3428f1580f4eSBarry Smith . type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`
3429b02e2d75SMatthew G Knepley 
3430feefa0e1SJacob Faibussowitsch   Level: intermediate
3431b02e2d75SMatthew G Knepley 
343260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCompositeSetType()`, `PCFIELDSPLIT`, `PCCompositeType`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`,
3433f1580f4eSBarry Smith           `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`
3434b02e2d75SMatthew G Knepley @*/
3435d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type)
3436d71ae5a4SJacob Faibussowitsch {
3437b02e2d75SMatthew G Knepley   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3438b02e2d75SMatthew G Knepley 
3439b02e2d75SMatthew G Knepley   PetscFunctionBegin;
3440b02e2d75SMatthew G Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
34414f572ea9SToby Isaac   PetscAssertPointer(type, 2);
3442b02e2d75SMatthew G Knepley   *type = jac->type;
34433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3444b02e2d75SMatthew G Knepley }
3445b02e2d75SMatthew G Knepley 
34464ab8060aSDmitry Karpeev /*@
3447f1580f4eSBarry Smith   PCFieldSplitSetDMSplits - Flags whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible.
34484ab8060aSDmitry Karpeev 
3449c3339decSBarry Smith   Logically Collective
34504ab8060aSDmitry Karpeev 
34514ab8060aSDmitry Karpeev   Input Parameters:
34524ab8060aSDmitry Karpeev + pc  - the preconditioner context
3453f1580f4eSBarry Smith - flg - boolean indicating whether to use field splits defined by the `DM`
34544ab8060aSDmitry Karpeev 
34554ab8060aSDmitry Karpeev   Options Database Key:
3456f1580f4eSBarry Smith . -pc_fieldsplit_dm_splits <bool> - use the field splits defined by the `DM`
34574ab8060aSDmitry Karpeev 
3458feefa0e1SJacob Faibussowitsch   Level: intermediate
34594ab8060aSDmitry Karpeev 
346073ff1848SBarry Smith   Developer Note:
346173ff1848SBarry Smith   The name should be `PCFieldSplitSetUseDMSplits()`, similar change to options database
346273ff1848SBarry Smith 
3463f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
34644ab8060aSDmitry Karpeev @*/
3465d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDMSplits(PC pc, PetscBool flg)
3466d71ae5a4SJacob Faibussowitsch {
34674ab8060aSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
34684ab8060aSDmitry Karpeev   PetscBool      isfs;
34694ab8060aSDmitry Karpeev 
34704ab8060aSDmitry Karpeev   PetscFunctionBegin;
34714ab8060aSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
34724ab8060aSDmitry Karpeev   PetscValidLogicalCollectiveBool(pc, flg, 2);
34739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
3474ad540459SPierre Jolivet   if (isfs) jac->dm_splits = flg;
34753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34764ab8060aSDmitry Karpeev }
34774ab8060aSDmitry Karpeev 
34784ab8060aSDmitry Karpeev /*@
3479f1580f4eSBarry Smith   PCFieldSplitGetDMSplits - Returns flag indicating whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible.
34804ab8060aSDmitry Karpeev 
34814ab8060aSDmitry Karpeev   Logically Collective
34824ab8060aSDmitry Karpeev 
34834ab8060aSDmitry Karpeev   Input Parameter:
34844ab8060aSDmitry Karpeev . pc - the preconditioner context
34854ab8060aSDmitry Karpeev 
34864ab8060aSDmitry Karpeev   Output Parameter:
3487f1580f4eSBarry Smith . flg - boolean indicating whether to use field splits defined by the `DM`
34884ab8060aSDmitry Karpeev 
3489feefa0e1SJacob Faibussowitsch   Level: intermediate
34904ab8060aSDmitry Karpeev 
349173ff1848SBarry Smith   Developer Note:
349273ff1848SBarry Smith   The name should be `PCFieldSplitGetUseDMSplits()`
349373ff1848SBarry Smith 
3494f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
34954ab8060aSDmitry Karpeev @*/
3496d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDMSplits(PC pc, PetscBool *flg)
3497d71ae5a4SJacob Faibussowitsch {
34984ab8060aSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
34994ab8060aSDmitry Karpeev   PetscBool      isfs;
35004ab8060aSDmitry Karpeev 
35014ab8060aSDmitry Karpeev   PetscFunctionBegin;
35024ab8060aSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
35034f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
35049566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
35054ab8060aSDmitry Karpeev   if (isfs) {
35064ab8060aSDmitry Karpeev     if (flg) *flg = jac->dm_splits;
35074ab8060aSDmitry Karpeev   }
35083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35094ab8060aSDmitry Karpeev }
35104ab8060aSDmitry Karpeev 
35117b752e3dSPatrick Sanan /*@
3512f1580f4eSBarry Smith   PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries.
35137b752e3dSPatrick Sanan 
35147b752e3dSPatrick Sanan   Logically Collective
35157b752e3dSPatrick Sanan 
35167b752e3dSPatrick Sanan   Input Parameter:
35177b752e3dSPatrick Sanan . pc - the preconditioner context
35187b752e3dSPatrick Sanan 
35197b752e3dSPatrick Sanan   Output Parameter:
35207b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not
35217b752e3dSPatrick Sanan 
3522feefa0e1SJacob Faibussowitsch   Level: intermediate
35237b752e3dSPatrick Sanan 
352460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()`
35257b752e3dSPatrick Sanan @*/
3526d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc, PetscBool *flg)
3527d71ae5a4SJacob Faibussowitsch {
35287b752e3dSPatrick Sanan   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35297b752e3dSPatrick Sanan 
35307b752e3dSPatrick Sanan   PetscFunctionBegin;
35317b752e3dSPatrick Sanan   *flg = jac->detect;
35323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35337b752e3dSPatrick Sanan }
35347b752e3dSPatrick Sanan 
35357b752e3dSPatrick Sanan /*@
3536f1580f4eSBarry Smith   PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries.
35377b752e3dSPatrick Sanan 
35387b752e3dSPatrick Sanan   Logically Collective
35397b752e3dSPatrick Sanan 
35407b752e3dSPatrick Sanan   Input Parameter:
35417b752e3dSPatrick Sanan . pc - the preconditioner context
35427b752e3dSPatrick Sanan 
35437b752e3dSPatrick Sanan   Output Parameter:
35447b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not
35457b752e3dSPatrick Sanan 
35467b752e3dSPatrick Sanan   Options Database Key:
3547147403d9SBarry Smith . -pc_fieldsplit_detect_saddle_point <bool> - detect and use the saddle point
3548147403d9SBarry Smith 
3549feefa0e1SJacob Faibussowitsch   Level: intermediate
355060f59c3bSBarry Smith 
3551f1580f4eSBarry Smith   Note:
3552f1580f4eSBarry 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()`).
35537b752e3dSPatrick Sanan 
355460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDetectSaddlePoint()`, `PCFieldSplitSetType()`, `PCFieldSplitSetSchurPre()`, `PC_FIELDSPLIT_SCHUR_PRE_SELF`
35557b752e3dSPatrick Sanan @*/
3556d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc, PetscBool flg)
3557d71ae5a4SJacob Faibussowitsch {
35587b752e3dSPatrick Sanan   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
35597b752e3dSPatrick Sanan 
35607b752e3dSPatrick Sanan   PetscFunctionBegin;
35617b752e3dSPatrick Sanan   jac->detect = flg;
35627b752e3dSPatrick Sanan   if (jac->detect) {
35639566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR));
35649566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL));
35657b752e3dSPatrick Sanan   }
35663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35677b752e3dSPatrick Sanan }
35687b752e3dSPatrick Sanan 
35690971522cSBarry Smith /*MC
3570a8c7a070SBarry Smith   PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
35710b4b7b1cSBarry Smith   collections of variables (that may overlap) called fields or splits. Each field often represents a different continuum variable
35720b4b7b1cSBarry Smith   represented on a grid, such as velocity, pressure, or temperature.
35730b4b7b1cSBarry Smith   In the literature these are sometimes called block preconditioners; but should not be confused with `PCBJACOBI`.
35740b4b7b1cSBarry Smith   See [the users manual section on "Solving Block Matrices"](sec_block_matrices) for more details.
35750971522cSBarry Smith 
357679416396SBarry Smith   Options Database Keys:
3577de37d9f1SPatrick Sanan +   -pc_fieldsplit_%d_fields <a,b,..>                                                - indicates the fields to be used in the `%d`'th split
357881540f2fSBarry Smith .   -pc_fieldsplit_default                                                           - automatically add any fields to additional splits that have not
3579de37d9f1SPatrick Sanan                                                                                        been supplied explicitly by `-pc_fieldsplit_%d_fields`
358081540f2fSBarry Smith .   -pc_fieldsplit_block_size <bs>                                                   - size of block that defines fields (i.e. there are bs fields)
358180670ca5SBarry Smith                                                                                        when the matrix is not of `MatType` `MATNEST`
3582a51937d4SCarola Kruse .   -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting
3583d59693daSPierre Jolivet .   -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full>                     - default is `a11`; see `PCFieldSplitSetSchurPre()`
35841d27aa22SBarry Smith .   -pc_fieldsplit_schur_fact_type <diag,lower,upper,full>                           - set factorization type when using `-pc_fieldsplit_type schur`;
35851d27aa22SBarry Smith                                                                                        see `PCFieldSplitSetSchurFactType()`
358673ff1848SBarry Smith .   -pc_fieldsplit_dm_splits <true,false> (default is true)                          - Whether to use `DMCreateFieldDecomposition()` for splits
3587fb6809a2SPatrick Sanan -   -pc_fieldsplit_detect_saddle_point                                               - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver
358879416396SBarry Smith 
3589de37d9f1SPatrick Sanan   Options prefixes for inner solvers when using the Schur complement preconditioner are `-fieldsplit_0_` and `-fieldsplit_1_` .
3590de37d9f1SPatrick Sanan   The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is `-fieldsplit_0_`
359160f59c3bSBarry Smith   For all other solvers they are `-fieldsplit_%d_` for the `%d`'th field; use `-fieldsplit_` for all fields.
359260f59c3bSBarry Smith 
359322399129SNuno Nobre   To set options on the solvers for all blocks, prepend `-fieldsplit_` to all the `PC`
359422399129SNuno Nobre   options database keys. For example, `-fieldsplit_pc_type ilu` `-fieldsplit_pc_factor_levels 1`.
359560f59c3bSBarry Smith 
359660f59c3bSBarry Smith   To set the options on the solvers separate for each block call `PCFieldSplitGetSubKSP()`
359760f59c3bSBarry Smith   and set the options directly on the resulting `KSP` object
359860f59c3bSBarry Smith 
359960f59c3bSBarry Smith   Level: intermediate
36005d4c12cdSJungho Lee 
3601c8a0d604SMatthew G Knepley   Notes:
360280670ca5SBarry Smith   Use `PCFieldSplitSetFields()` to set splits defined by "strided" entries or with a `MATNEST` and `PCFieldSplitSetIS()`
3603f1580f4eSBarry Smith   to define a split by an arbitrary collection of entries.
3604d32f9abdSBarry Smith 
360573ff1848SBarry Smith   If no splits are set, the default is used. If a `DM` is associated with the `PC` and it supports
360680670ca5SBarry 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,
3607de37d9f1SPatrick Sanan   beginning at 0 then 1, etc to bs-1. The block size can be set with `PCFieldSplitSetBlockSize()`,
3608d32f9abdSBarry Smith   if this is not called the block size defaults to the blocksize of the second matrix passed
3609de37d9f1SPatrick Sanan   to `KSPSetOperators()`/`PCSetOperators()`.
3610d32f9abdSBarry Smith 
3611de37d9f1SPatrick Sanan   For the Schur complement preconditioner if
3612de37d9f1SPatrick Sanan   ```{math}
3613de37d9f1SPatrick Sanan     J = \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{10} & A_{11} \end{array}\right]
3614de37d9f1SPatrick Sanan   ```
3615e69d4d44SBarry Smith 
3616de37d9f1SPatrick Sanan   the preconditioner using `full` factorization is logically
3617de37d9f1SPatrick Sanan   ```{math}
3618f820a28cSNuno 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]
3619de37d9f1SPatrick Sanan       ```
3620cee94454SNuno Nobre   where the action of $\text{ksp}(A_{00})$ is applied using the `KSP` solver with prefix `-fieldsplit_0_`.  $S$ is the Schur complement
3621de37d9f1SPatrick Sanan   ```{math}
3622223e5b4fSPatrick Sanan      S = A_{11} - A_{10} \text{ksp}(A_{00}) A_{01}
3623de37d9f1SPatrick Sanan   ```
36247cbeddf0SNuno 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`
36257cbeddf0SNuno 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
36267cbeddf0SNuno Nobre   0th index, the `KSP` associated with `-fieldsplit_0_`, and at its 1st index, the `KSP` corresponding to `-fieldsplit_1_`.
3627d82b6cdfSNuno 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$.
3628de37d9f1SPatrick Sanan 
3629de37d9f1SPatrick Sanan   The factorization type is set using `-pc_fieldsplit_schur_fact_type <diag, lower, upper, full>`. `full` is shown above,
3630de37d9f1SPatrick Sanan   `diag` gives
3631de37d9f1SPatrick Sanan   ```{math}
3632f820a28cSNuno Nobre     \left[\begin{array}{cc} \text{ksp}(A_{00}) & 0 \\  0 & -\text{ksp}(S) \end{array}\right]
3633de37d9f1SPatrick Sanan   ```
3634de37d9f1SPatrick 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
3635de37d9f1SPatrick Sanan   can be turned off with `PCFieldSplitSetSchurScale()` or by command line `-pc_fieldsplit_schur_scale 1.0`. The `lower` factorization is the inverse of
3636de37d9f1SPatrick Sanan   ```{math}
3637de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & 0 \\  A_{10} & S \end{array}\right]
3638de37d9f1SPatrick Sanan   ```
3639cee94454SNuno Nobre   where the inverses of $A_{00}$ and $S$ are applied using `KSP`s. The upper factorization is the inverse of
3640de37d9f1SPatrick Sanan   ```{math}
3641de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & A_{01} \\  0 & S \end{array}\right]
3642de37d9f1SPatrick Sanan   ```
3643de37d9f1SPatrick Sanan   where again the inverses of $A_{00}$ and $S$ are applied using `KSP`s.
3644de37d9f1SPatrick Sanan 
3645de37d9f1SPatrick Sanan   If only one set of indices (one `IS`) is provided with `PCFieldSplitSetIS()` then the complement of that `IS`
364680670ca5SBarry Smith   is used automatically for a second submatrix.
3647edf189efSBarry Smith 
3648f1580f4eSBarry Smith   The fieldsplit preconditioner cannot currently be used with the `MATBAIJ` or `MATSBAIJ` data formats if the blocksize is larger than 1.
364980670ca5SBarry Smith   Generally it should be used with the `MATAIJ` or `MATNEST` `MatType`
3650ff218e97SBarry Smith 
365180670ca5SBarry Smith   The forms of these preconditioners are closely related, if not identical, to forms derived as "Distributive Iterations", see,
36521d569b8fSBarry Smith   for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling {cite}`wesseling2009`.
365380670ca5SBarry Smith   One can also use `PCFIELDSPLIT` inside a smoother resulting in "Distributive Smoothers".
36540716a85fSBarry Smith 
3655de37d9f1SPatrick Sanan   See "A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations" {cite}`elman2008tcp`.
3656a6a584a2SBarry Smith 
3657de37d9f1SPatrick Sanan   The Constrained Pressure Preconditioner (CPR) can be implemented using `PCCOMPOSITE` with `PCGALERKIN`. CPR first solves an $R A P$ subsystem, updates the
3658de37d9f1SPatrick Sanan   residual on all variables (`PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)`), and then applies a simple ILU like preconditioner on all the variables.
3659a51937d4SCarola Kruse 
3660de37d9f1SPatrick Sanan   The generalized Golub-Kahan bidiagonalization preconditioner (GKB) can be applied to symmetric $2 \times 2$ block matrices of the shape
3661de37d9f1SPatrick Sanan   ```{math}
3662de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{01}' & 0 \end{array}\right]
3663de37d9f1SPatrick Sanan   ```
36641d569b8fSBarry 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}'$.
3665de37d9f1SPatrick 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_`.
3666a51937d4SCarola Kruse 
36670b4b7b1cSBarry Smith   Some `PCFIELDSPLIT` variants are called physics-based preconditioners, since the preconditioner takes into account the underlying physics of the
36680b4b7b1cSBarry Smith   problem. But this nomenclature is not well-defined.
36690b4b7b1cSBarry Smith 
367060f59c3bSBarry Smith   Developer Note:
367160f59c3bSBarry Smith   The Schur complement functionality of `PCFIELDSPLIT` should likely be factored into its own `PC` thus simplifying the implementation of the preconditioners and their
367260f59c3bSBarry Smith   user API.
3673f1580f4eSBarry Smith 
367460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCLSC`,
3675db781477SPatrick Sanan           `PCFieldSplitGetSubKSP()`, `PCFieldSplitSchurGetSubKSP()`, `PCFieldSplitSetFields()`,
3676db781477SPatrick Sanan           `PCFieldSplitSetType()`, `PCFieldSplitSetIS()`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitSetSchurFactType()`,
3677db781477SPatrick Sanan           `MatSchurComplementSetAinvType()`, `PCFieldSplitSetSchurScale()`, `PCFieldSplitSetDetectSaddlePoint()`
36780971522cSBarry Smith M*/
36790971522cSBarry Smith 
3680d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc)
3681d71ae5a4SJacob Faibussowitsch {
36820971522cSBarry Smith   PC_FieldSplit *jac;
36830971522cSBarry Smith 
36840971522cSBarry Smith   PetscFunctionBegin;
36854dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&jac));
36862fa5cd67SKarl Rupp 
36870971522cSBarry Smith   jac->bs                 = -1;
36883e197d65SBarry Smith   jac->type               = PC_COMPOSITE_MULTIPLICATIVE;
3689e6cab6aaSJed Brown   jac->schurpre           = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
3690c9c6ffaaSJed Brown   jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL;
3691c096484dSStefano Zampini   jac->schurscale         = -1.0;
3692fbe7908bSJed Brown   jac->dm_splits          = PETSC_TRUE;
3693a51937d4SCarola Kruse   jac->gkbtol             = 1e-5;
3694a51937d4SCarola Kruse   jac->gkbdelay           = 5;
3695a51937d4SCarola Kruse   jac->gkbnu              = 1;
3696a51937d4SCarola Kruse   jac->gkbmaxit           = 100;
369751f519a2SBarry Smith 
36980971522cSBarry Smith   pc->data = (void *)jac;
36990971522cSBarry Smith 
37000971522cSBarry Smith   pc->ops->setup           = PCSetUp_FieldSplit;
3701574deadeSBarry Smith   pc->ops->reset           = PCReset_FieldSplit;
37020971522cSBarry Smith   pc->ops->destroy         = PCDestroy_FieldSplit;
37030971522cSBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_FieldSplit;
37040a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
37050971522cSBarry Smith 
37069566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", PCFieldSplitSchurGetSubKSP_FieldSplit));
37079566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", PCFieldSplitSetFields_FieldSplit));
37089566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_FieldSplit));
37099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", PCFieldSplitSetType_FieldSplit));
37109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", PCFieldSplitSetBlockSize_FieldSplit));
37119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", PCFieldSplitRestrictIS_FieldSplit));
37129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_FieldSplit));
37137ff38633SStefano Zampini 
37147ff38633SStefano Zampini   /* Initialize function pointers */
37157ff38633SStefano Zampini   PetscCall(PCFieldSplitSetType(pc, jac->type));
37163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37170971522cSBarry Smith }
3718