xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision d484b38499953fbf56fc48e9f43f331c10de329f)
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 ....*/
3*d484b384SBoris 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*d484b384SBoris Martin   Mat               X, Y;
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 
1336*d484b384SBoris Martin /*
1337*d484b384SBoris Martin   PCFieldSplitCreateWorkMats_Private - Allocate per-field dense work matrices for multi-RHS
1338*d484b384SBoris Martin 
1339*d484b384SBoris Martin   Input Parameters:
1340*d484b384SBoris Martin + pc - the PC context
1341*d484b384SBoris Martin - X  - matrix to copy column-layout from
1342*d484b384SBoris Martin 
1343*d484b384SBoris Martin   Notes:
1344*d484b384SBoris Martin   If matrices already exist with correct column count, they are reused.
1345*d484b384SBoris Martin   If column count changed, old matrices are destroyed and new ones created.
1346*d484b384SBoris Martin */
1347*d484b384SBoris Martin static PetscErrorCode PCFieldSplitCreateWorkMats_Private(PC pc, Mat X)
1348*d484b384SBoris Martin {
1349*d484b384SBoris Martin   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1350*d484b384SBoris Martin   PC_FieldSplitLink ilink = jac->head;
1351*d484b384SBoris Martin   PetscInt          mx, Mx, my, My, N;
1352*d484b384SBoris Martin 
1353*d484b384SBoris Martin   PetscFunctionBegin;
1354*d484b384SBoris Martin   while (ilink) {
1355*d484b384SBoris Martin     /* check if reallocation needed (previous allocation with wrong column count) */
1356*d484b384SBoris Martin     if (ilink->X) {
1357*d484b384SBoris Martin       PetscCall(MatGetSize(ilink->X, NULL, &N));
1358*d484b384SBoris Martin       if (N != X->cmap->N) {
1359*d484b384SBoris Martin         PetscCall(MatDestroy(&ilink->X));
1360*d484b384SBoris Martin         PetscCall(MatDestroy(&ilink->Y));
1361*d484b384SBoris Martin       }
1362*d484b384SBoris Martin     }
1363*d484b384SBoris Martin     /* create if needed */
1364*d484b384SBoris Martin     if (!ilink->X) {
1365*d484b384SBoris Martin       VecType xtype, ytype;
1366*d484b384SBoris Martin 
1367*d484b384SBoris Martin       PetscCall(VecGetType(ilink->x, &xtype));
1368*d484b384SBoris Martin       PetscCall(VecGetType(ilink->y, &ytype));
1369*d484b384SBoris Martin       PetscCall(VecGetLocalSize(ilink->x, &mx));
1370*d484b384SBoris Martin       PetscCall(VecGetSize(ilink->x, &Mx));
1371*d484b384SBoris Martin       PetscCall(VecGetLocalSize(ilink->y, &my));
1372*d484b384SBoris Martin       PetscCall(VecGetSize(ilink->y, &My));
1373*d484b384SBoris Martin       /* use default lda */
1374*d484b384SBoris Martin       PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), xtype, mx, X->cmap->n, Mx, X->cmap->N, -1, NULL, &ilink->X));
1375*d484b384SBoris Martin       PetscCall(MatCreateDenseFromVecType(PetscObjectComm((PetscObject)pc), ytype, my, X->cmap->n, My, X->cmap->N, -1, NULL, &ilink->Y));
1376*d484b384SBoris Martin     }
1377*d484b384SBoris Martin     ilink = ilink->next;
1378*d484b384SBoris Martin   }
1379*d484b384SBoris Martin   PetscFunctionReturn(PETSC_SUCCESS);
1380*d484b384SBoris Martin }
1381*d484b384SBoris Martin 
13827b665727SPierre Jolivet static PetscErrorCode PCApplyTranspose_FieldSplit_Schur(PC pc, Vec x, Vec y)
13837b665727SPierre Jolivet {
13847b665727SPierre Jolivet   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
13857b665727SPierre Jolivet   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
13867b665727SPierre Jolivet   KSP               kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
13877b665727SPierre Jolivet 
13887b665727SPierre Jolivet   PetscFunctionBegin;
13897b665727SPierre Jolivet   switch (jac->schurfactorization) {
13907b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
13917b665727SPierre Jolivet     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
13927b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
13937b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
13947b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
13957b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
13967b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
13977b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
13987b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
13997b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
14007b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
14017b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1402e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
14037b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1404e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
14057b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
14067b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
14077b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->y, jac->schurscale));
14087b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
14097b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
14107b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
14117b665727SPierre Jolivet     break;
14127b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
14137b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
14147b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
14157b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
14167b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
14177b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
14187b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
14197b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x));
14207b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->x, -1.));
14217b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
14227b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
14237b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
14247b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1425e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
14267b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1427e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
14287b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
14297b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
14307b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
14317b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
14327b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
14337b665727SPierre Jolivet     break;
14347b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
14357b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
14367b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
14377b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1438e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
14397b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1440e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
14417b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
14427b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
14437b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x));
14447b665727SPierre Jolivet     PetscCall(VecScale(ilinkA->x, -1.));
14457b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
14467b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
14477b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
14487b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
14497b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
14507b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
14517b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
14527b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
14537b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
14547b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
14557b665727SPierre Jolivet     break;
14567b665727SPierre Jolivet   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
14577b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
14587b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
14597b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL));
14607b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(kspUpper, ilinkA->x, ilinkA->y));
14617b665727SPierre Jolivet     PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->y));
14627b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->y, NULL));
14637b665727SPierre Jolivet     PetscCall(MatMultTranspose(jac->B, ilinkA->y, ilinkD->x));
14647b665727SPierre Jolivet     PetscCall(VecScale(ilinkD->x, -1.0));
14657b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
14667b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
14677b665727SPierre Jolivet 
14687b665727SPierre Jolivet     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1469e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, 1));
14707b665727SPierre Jolivet     PetscCall(KSPSolveTranspose(jac->kspschur, ilinkD->x, ilinkD->y));
1471e0b7e82fSBarry Smith     PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspA, (PetscObject)kspA, -1));
14727b665727SPierre Jolivet     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
14737b665727SPierre Jolivet     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
14747b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
14757b665727SPierre Jolivet 
14767b665727SPierre Jolivet     if (kspLower == kspA) {
14777b665727SPierre Jolivet       PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->y));
14787b665727SPierre Jolivet       PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y));
14797b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
14807b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
14817b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
14827b665727SPierre Jolivet       PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
14837b665727SPierre Jolivet     } else {
14847b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
14857b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspA, ilinkA->x, ilinkA->y));
14867b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
14877b665727SPierre Jolivet       PetscCall(MatMultTranspose(jac->C, ilinkD->y, ilinkA->x));
14887b665727SPierre Jolivet       PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL));
14897b665727SPierre Jolivet       PetscCall(KSPSolveTranspose(kspLower, ilinkA->x, ilinkA->z));
14907b665727SPierre Jolivet       PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->z));
14917b665727SPierre Jolivet       PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->z, NULL));
14927b665727SPierre Jolivet       PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z));
14937b665727SPierre Jolivet     }
14947b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
14957b665727SPierre Jolivet     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
14967b665727SPierre Jolivet     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
14977b665727SPierre Jolivet   }
14987b665727SPierre Jolivet   PetscFunctionReturn(PETSC_SUCCESS);
14997b665727SPierre Jolivet }
15007b665727SPierre Jolivet 
15015becce15SPierre Jolivet #define FieldSplitSplitSolveAdd(ilink, xx, yy) \
15025becce15SPierre 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) || \
15035becce15SPierre 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) || \
15045becce15SPierre Jolivet                     VecScatterEnd(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE)))
15055becce15SPierre Jolivet 
1506d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit(PC pc, Vec x, Vec y)
1507d71ae5a4SJacob Faibussowitsch {
15080971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
15095a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
1510939b8a20SBarry Smith   PetscInt          cnt, bs;
15110971522cSBarry Smith 
15120971522cSBarry Smith   PetscFunctionBegin;
151379416396SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
151480670ca5SBarry Smith     PetscBool matnest;
151580670ca5SBarry Smith 
151680670ca5SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
151780670ca5SBarry Smith     if (jac->defaultsplit && !matnest) {
15189566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(x, &bs));
15192472a847SBarry 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);
15209566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(y, &bs));
15212472a847SBarry 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);
15229566063dSJacob Faibussowitsch       PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
15235a9f2f41SSatish Balay       while (ilink) {
15249566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15259566063dSJacob Faibussowitsch         PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
15269566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
15279566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15285a9f2f41SSatish Balay         ilink = ilink->next;
15290971522cSBarry Smith       }
15309566063dSJacob Faibussowitsch       PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
15311b9fc7fcSBarry Smith     } else {
15329566063dSJacob Faibussowitsch       PetscCall(VecSet(y, 0.0));
15335a9f2f41SSatish Balay       while (ilink) {
15349566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
15355a9f2f41SSatish Balay         ilink = ilink->next;
15361b9fc7fcSBarry Smith       }
15371b9fc7fcSBarry Smith     }
1538e52d2c62SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
15399566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
1540e52d2c62SBarry Smith     /* solve on first block for first block variables */
15419566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
15429566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
15439566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15449566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
15459566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
15469566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15479566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
15489566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1549e52d2c62SBarry Smith 
1550e52d2c62SBarry Smith     /* compute the residual only onto second block variables using first block variables */
15519566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->Afield[1], ilink->y, ilink->next->x));
1552e52d2c62SBarry Smith     ilink = ilink->next;
15539566063dSJacob Faibussowitsch     PetscCall(VecScale(ilink->x, -1.0));
15549566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
15559566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1556e52d2c62SBarry Smith 
1557e52d2c62SBarry Smith     /* solve on second block variables */
15589566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15599566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
15609566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
15619566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15629566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
15639566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
156416913363SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
156579416396SBarry Smith     if (!jac->w1) {
15669566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w1));
15679566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w2));
156879416396SBarry Smith     }
15699566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
15709566063dSJacob Faibussowitsch     PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
15713e197d65SBarry Smith     cnt = 1;
15725a9f2f41SSatish Balay     while (ilink->next) {
15735a9f2f41SSatish Balay       ilink = ilink->next;
15743e197d65SBarry Smith       /* compute the residual only over the part of the vector needed */
15759566063dSJacob Faibussowitsch       PetscCall(MatMult(jac->Afield[cnt++], y, ilink->x));
15769566063dSJacob Faibussowitsch       PetscCall(VecScale(ilink->x, -1.0));
15779566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
15789566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
15799566063dSJacob Faibussowitsch       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15809566063dSJacob Faibussowitsch       PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
15819566063dSJacob Faibussowitsch       PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
15829566063dSJacob Faibussowitsch       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15839566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
15849566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
15853e197d65SBarry Smith     }
158651f519a2SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
158711755939SBarry Smith       cnt -= 2;
158851f519a2SBarry Smith       while (ilink->previous) {
158951f519a2SBarry Smith         ilink = ilink->previous;
159011755939SBarry Smith         /* compute the residual only over the part of the vector needed */
15919566063dSJacob Faibussowitsch         PetscCall(MatMult(jac->Afield[cnt--], y, ilink->x));
15929566063dSJacob Faibussowitsch         PetscCall(VecScale(ilink->x, -1.0));
15939566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
15949566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
15959566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15969566063dSJacob Faibussowitsch         PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
15979566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
15989566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
15999566063dSJacob Faibussowitsch         PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
16009566063dSJacob Faibussowitsch         PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
160151f519a2SBarry Smith       }
160211755939SBarry Smith     }
160363a3b9bcSJacob Faibussowitsch   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)jac->type);
16043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16050971522cSBarry Smith }
16060971522cSBarry Smith 
1607*d484b384SBoris Martin static PetscErrorCode PCMatApply_FieldSplit(PC pc, Mat X, Mat Y)
1608*d484b384SBoris Martin {
1609*d484b384SBoris Martin   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1610*d484b384SBoris Martin   PC_FieldSplitLink ilink = jac->head;
1611*d484b384SBoris Martin   PetscInt          cnt;
1612*d484b384SBoris Martin 
1613*d484b384SBoris Martin   PetscFunctionBegin;
1614*d484b384SBoris Martin   /* create working matrices with the correct number of columns */
1615*d484b384SBoris Martin   PetscCall(PCFieldSplitCreateWorkMats_Private(pc, X));
1616*d484b384SBoris Martin   if (jac->type == PC_COMPOSITE_ADDITIVE) {
1617*d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
1618*d484b384SBoris Martin     while (ilink) {
1619*d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1620*d484b384SBoris Martin       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1621*d484b384SBoris Martin       PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1622*d484b384SBoris Martin       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1623*d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1624*d484b384SBoris Martin       ilink = ilink->next;
1625*d484b384SBoris Martin     }
1626*d484b384SBoris Martin   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
1627*d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
1628*d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1629*d484b384SBoris Martin     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1630*d484b384SBoris Martin     PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1631*d484b384SBoris Martin     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1632*d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1633*d484b384SBoris Martin 
1634*d484b384SBoris Martin     /* compute the residual only onto second block variables using first block variables */
1635*d484b384SBoris Martin     PetscCall(MatMatMult(jac->Afield[1], ilink->Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->next->X));
1636*d484b384SBoris Martin     ilink = ilink->next;
1637*d484b384SBoris Martin     PetscCall(MatScale(ilink->X, -1.0));
1638*d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1639*d484b384SBoris Martin 
1640*d484b384SBoris Martin     /* solve on second block variables */
1641*d484b384SBoris Martin     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1642*d484b384SBoris Martin     PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1643*d484b384SBoris Martin     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1644*d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1645*d484b384SBoris Martin   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1646*d484b384SBoris Martin     /* general multiplicative with any number of splits */
1647*d484b384SBoris Martin     PetscCall(MatZeroEntries(Y));
1648*d484b384SBoris Martin     /* first split */
1649*d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, INSERT_VALUES, SCATTER_FORWARD));
1650*d484b384SBoris Martin     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1651*d484b384SBoris Martin     PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1652*d484b384SBoris Martin     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1653*d484b384SBoris Martin     PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1654*d484b384SBoris Martin     cnt = 1;
1655*d484b384SBoris Martin     /* forward sweep */
1656*d484b384SBoris Martin     while (ilink->next) {
1657*d484b384SBoris Martin       ilink = ilink->next;
1658*d484b384SBoris Martin       /* compute the residual only over the part of the vector needed */
1659*d484b384SBoris Martin       PetscCall(MatMatMult(jac->Afield[cnt++], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X));
1660*d484b384SBoris Martin       PetscCall(MatScale(ilink->X, -1.0));
1661*d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1662*d484b384SBoris Martin       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1663*d484b384SBoris Martin       PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1664*d484b384SBoris Martin       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1665*d484b384SBoris Martin       PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1666*d484b384SBoris Martin     }
1667*d484b384SBoris Martin     /* backward sweep for symmetric multiplicative */
1668*d484b384SBoris Martin     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1669*d484b384SBoris Martin       cnt -= 2;
1670*d484b384SBoris Martin       while (ilink->previous) {
1671*d484b384SBoris Martin         ilink = ilink->previous;
1672*d484b384SBoris Martin         /* compute the residual only over the part of the vector needed */
1673*d484b384SBoris Martin         PetscCall(MatMatMult(jac->Afield[cnt--], Y, MAT_REUSE_MATRIX, PETSC_DETERMINE, &ilink->X));
1674*d484b384SBoris Martin         PetscCall(MatScale(ilink->X, -1.0));
1675*d484b384SBoris Martin         PetscCall(MatDenseScatter_Private(ilink->sctx, X, ilink->X, ADD_VALUES, SCATTER_FORWARD));
1676*d484b384SBoris Martin         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1677*d484b384SBoris Martin         PetscCall(KSPMatSolve(ilink->ksp, ilink->X, ilink->Y));
1678*d484b384SBoris Martin         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->X, ilink->Y, NULL));
1679*d484b384SBoris Martin         PetscCall(MatDenseScatter_Private(ilink->sctx, ilink->Y, Y, ADD_VALUES, SCATTER_REVERSE));
1680*d484b384SBoris Martin       }
1681*d484b384SBoris Martin     }
1682*d484b384SBoris Martin   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "PCMatApply() not implemented for this fieldsplit type");
1683*d484b384SBoris Martin   PetscFunctionReturn(PETSC_SUCCESS);
1684*d484b384SBoris Martin }
1685*d484b384SBoris Martin 
1686d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApply_FieldSplit_GKB(PC pc, Vec x, Vec y)
1687d71ae5a4SJacob Faibussowitsch {
1688a51937d4SCarola Kruse   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
1689a51937d4SCarola Kruse   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1690a51937d4SCarola Kruse   KSP               ksp = ilinkA->ksp;
1691de482cd7SCarola Kruse   Vec               u, v, Hu, d, work1, work2;
1692e071a0a4SCarola Kruse   PetscScalar       alpha, z, nrmz2, *vecz;
1693e071a0a4SCarola Kruse   PetscReal         lowbnd, nu, beta;
1694a51937d4SCarola Kruse   PetscInt          j, iterGKB;
1695a51937d4SCarola Kruse 
1696a51937d4SCarola Kruse   PetscFunctionBegin;
16979566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
16989566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
16999566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
17009566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1701e071a0a4SCarola Kruse 
1702e071a0a4SCarola Kruse   u     = jac->u;
1703e071a0a4SCarola Kruse   v     = jac->v;
1704e071a0a4SCarola Kruse   Hu    = jac->Hu;
1705e071a0a4SCarola Kruse   d     = jac->d;
1706e071a0a4SCarola Kruse   work1 = jac->w1;
1707e071a0a4SCarola Kruse   work2 = jac->w2;
1708e071a0a4SCarola Kruse   vecz  = jac->vecz;
1709a51937d4SCarola Kruse 
1710a51937d4SCarola Kruse   /* Change RHS to comply with matrix regularization H = A + nu*B*B' */
1711a51937d4SCarola Kruse   /* Add q = q + nu*B*b */
1712a51937d4SCarola Kruse   if (jac->gkbnu) {
1713a51937d4SCarola Kruse     nu = jac->gkbnu;
17149566063dSJacob Faibussowitsch     PetscCall(VecScale(ilinkD->x, jac->gkbnu));
17159566063dSJacob Faibussowitsch     PetscCall(MatMultAdd(jac->B, ilinkD->x, ilinkA->x, ilinkA->x)); /* q = q + nu*B*b */
1716a51937d4SCarola Kruse   } else {
1717a51937d4SCarola Kruse     /* Situation when no augmented Lagrangian is used. Then we set inner  */
1718a51937d4SCarola Kruse     /* matrix N = I in [Ar13], and thus nu = 1.                           */
1719a51937d4SCarola Kruse     nu = 1;
1720a51937d4SCarola Kruse   }
1721a51937d4SCarola Kruse 
1722a51937d4SCarola Kruse   /* Transform rhs from [q,tilde{b}] to [0,b] */
17239566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
17249566063dSJacob Faibussowitsch   PetscCall(KSPSolve(ksp, ilinkA->x, ilinkA->y));
17259566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(ksp, pc, ilinkA->y));
17269566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
17279566063dSJacob Faibussowitsch   PetscCall(MatMultHermitianTranspose(jac->B, ilinkA->y, work1));
17289566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(work1, 1.0 / nu, -1.0, ilinkD->x)); /* c = b - B'*x        */
1729a51937d4SCarola Kruse 
1730a51937d4SCarola Kruse   /* First step of algorithm */
17319566063dSJacob Faibussowitsch   PetscCall(VecNorm(work1, NORM_2, &beta)); /* beta = sqrt(nu*c'*c)*/
1732e071a0a4SCarola Kruse   KSPCheckDot(ksp, beta);
1733addd1e01SJunchao Zhang   beta = PetscSqrtReal(nu) * beta;
17349566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(v, nu / beta, 0.0, work1)); /* v = nu/beta *c      */
17359566063dSJacob Faibussowitsch   PetscCall(MatMult(jac->B, v, work2));          /* u = H^{-1}*B*v      */
17369566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
17379566063dSJacob Faibussowitsch   PetscCall(KSPSolve(ksp, work2, u));
17389566063dSJacob Faibussowitsch   PetscCall(KSPCheckSolve(ksp, pc, u));
17399566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
17409566063dSJacob Faibussowitsch   PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u      */
17419566063dSJacob Faibussowitsch   PetscCall(VecDot(Hu, u, &alpha));
1742e071a0a4SCarola Kruse   KSPCheckDot(ksp, alpha);
174308401ef6SPierre Jolivet   PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1744addd1e01SJunchao Zhang   alpha = PetscSqrtReal(PetscAbsScalar(alpha));
17459566063dSJacob Faibussowitsch   PetscCall(VecScale(u, 1.0 / alpha));
17469566063dSJacob Faibussowitsch   PetscCall(VecAXPBY(d, 1.0 / alpha, 0.0, v)); /* v = nu/beta *c      */
1747de482cd7SCarola Kruse 
1748a51937d4SCarola Kruse   z       = beta / alpha;
1749a51937d4SCarola Kruse   vecz[1] = z;
1750a51937d4SCarola Kruse 
1751de482cd7SCarola Kruse   /* Computation of first iterate x(1) and p(1) */
17529566063dSJacob Faibussowitsch   PetscCall(VecAXPY(ilinkA->y, z, u));
17539566063dSJacob Faibussowitsch   PetscCall(VecCopy(d, ilinkD->y));
17549566063dSJacob Faibussowitsch   PetscCall(VecScale(ilinkD->y, -z));
1755a51937d4SCarola Kruse 
17569371c9d4SSatish Balay   iterGKB = 1;
17579371c9d4SSatish Balay   lowbnd  = 2 * jac->gkbtol;
175848a46eb9SPierre Jolivet   if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1759de482cd7SCarola Kruse 
1760a51937d4SCarola Kruse   while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) {
1761a51937d4SCarola Kruse     iterGKB += 1;
17629566063dSJacob Faibussowitsch     PetscCall(MatMultHermitianTranspose(jac->B, u, work1)); /* v <- nu*(B'*u-alpha/nu*v) */
17639566063dSJacob Faibussowitsch     PetscCall(VecAXPBY(v, nu, -alpha, work1));
17649566063dSJacob Faibussowitsch     PetscCall(VecNorm(v, NORM_2, &beta)); /* beta = sqrt(nu)*v'*v      */
1765addd1e01SJunchao Zhang     beta = beta / PetscSqrtReal(nu);
17669566063dSJacob Faibussowitsch     PetscCall(VecScale(v, 1.0 / beta));
17679566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->B, v, work2)); /* u <- H^{-1}*(B*v-beta*H*u) */
17689566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, u, Hu));
17699566063dSJacob Faibussowitsch     PetscCall(VecAXPY(work2, -beta, Hu));
17709566063dSJacob Faibussowitsch     PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
17719566063dSJacob Faibussowitsch     PetscCall(KSPSolve(ksp, work2, u));
17729566063dSJacob Faibussowitsch     PetscCall(KSPCheckSolve(ksp, pc, u));
17739566063dSJacob Faibussowitsch     PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
17749566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u            */
17759566063dSJacob Faibussowitsch     PetscCall(VecDot(Hu, u, &alpha));
1776e071a0a4SCarola Kruse     KSPCheckDot(ksp, alpha);
177708401ef6SPierre Jolivet     PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1778addd1e01SJunchao Zhang     alpha = PetscSqrtReal(PetscAbsScalar(alpha));
17799566063dSJacob Faibussowitsch     PetscCall(VecScale(u, 1.0 / alpha));
1780a51937d4SCarola Kruse 
1781e071a0a4SCarola Kruse     z       = -beta / alpha * z; /* z <- beta/alpha*z     */
1782a51937d4SCarola Kruse     vecz[0] = z;
1783a51937d4SCarola Kruse 
1784a51937d4SCarola Kruse     /* Computation of new iterate x(i+1) and p(i+1) */
17859566063dSJacob Faibussowitsch     PetscCall(VecAXPBY(d, 1.0 / alpha, -beta / alpha, v)); /* d = (v-beta*d)/alpha */
17869566063dSJacob Faibussowitsch     PetscCall(VecAXPY(ilinkA->y, z, u));                   /* r = r + z*u          */
17879566063dSJacob Faibussowitsch     PetscCall(VecAXPY(ilinkD->y, -z, d));                  /* p = p - z*d          */
17889566063dSJacob Faibussowitsch     PetscCall(MatMult(jac->H, ilinkA->y, Hu));             /* ||u||_H = u'*H*u     */
17899566063dSJacob Faibussowitsch     PetscCall(VecDot(Hu, ilinkA->y, &nrmz2));
1790a51937d4SCarola Kruse 
1791a51937d4SCarola Kruse     /* Compute Lower Bound estimate */
1792a51937d4SCarola Kruse     if (iterGKB > jac->gkbdelay) {
1793a51937d4SCarola Kruse       lowbnd = 0.0;
1794ad540459SPierre Jolivet       for (j = 0; j < jac->gkbdelay; j++) lowbnd += PetscAbsScalar(vecz[j] * vecz[j]);
1795addd1e01SJunchao Zhang       lowbnd = PetscSqrtReal(lowbnd / PetscAbsScalar(nrmz2));
1796a51937d4SCarola Kruse     }
1797a51937d4SCarola Kruse 
1798ad540459SPierre Jolivet     for (j = 0; j < jac->gkbdelay - 1; j++) vecz[jac->gkbdelay - j - 1] = vecz[jac->gkbdelay - j - 2];
179948a46eb9SPierre Jolivet     if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1800a51937d4SCarola Kruse   }
1801a51937d4SCarola Kruse 
18029566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
18039566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
18049566063dSJacob Faibussowitsch   PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
18059566063dSJacob Faibussowitsch   PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
18063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1807a51937d4SCarola Kruse }
1808a51937d4SCarola Kruse 
1809421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink, xx, yy) \
18103ba16761SJacob 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) || \
18119371c9d4SSatish 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) || \
18123ba16761SJacob Faibussowitsch                     VecScatterEnd(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE)))
1813421e10b8SBarry Smith 
1814d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc, Vec x, Vec y)
1815d71ae5a4SJacob Faibussowitsch {
1816421e10b8SBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1817421e10b8SBarry Smith   PC_FieldSplitLink ilink = jac->head;
1818939b8a20SBarry Smith   PetscInt          bs;
1819421e10b8SBarry Smith 
1820421e10b8SBarry Smith   PetscFunctionBegin;
1821421e10b8SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
182280670ca5SBarry Smith     PetscBool matnest;
182380670ca5SBarry Smith 
182480670ca5SBarry Smith     PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &matnest));
182580670ca5SBarry Smith     if (jac->defaultsplit && !matnest) {
18269566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(x, &bs));
18272472a847SBarry 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);
18289566063dSJacob Faibussowitsch       PetscCall(VecGetBlockSize(y, &bs));
18292472a847SBarry 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);
18309566063dSJacob Faibussowitsch       PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
1831421e10b8SBarry Smith       while (ilink) {
18329566063dSJacob Faibussowitsch         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
18339566063dSJacob Faibussowitsch         PetscCall(KSPSolveTranspose(ilink->ksp, ilink->x, ilink->y));
18349566063dSJacob Faibussowitsch         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
18359566063dSJacob Faibussowitsch         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1836421e10b8SBarry Smith         ilink = ilink->next;
1837421e10b8SBarry Smith       }
18389566063dSJacob Faibussowitsch       PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
1839421e10b8SBarry Smith     } else {
18409566063dSJacob Faibussowitsch       PetscCall(VecSet(y, 0.0));
1841421e10b8SBarry Smith       while (ilink) {
18429566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
1843421e10b8SBarry Smith         ilink = ilink->next;
1844421e10b8SBarry Smith       }
1845421e10b8SBarry Smith     }
1846421e10b8SBarry Smith   } else {
1847421e10b8SBarry Smith     if (!jac->w1) {
18489566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w1));
18499566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(x, &jac->w2));
1850421e10b8SBarry Smith     }
18519566063dSJacob Faibussowitsch     PetscCall(VecSet(y, 0.0));
1852421e10b8SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
18539566063dSJacob Faibussowitsch       PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
1854421e10b8SBarry Smith       while (ilink->next) {
1855421e10b8SBarry Smith         ilink = ilink->next;
18569566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
18579566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
18589566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
1859421e10b8SBarry Smith       }
1860421e10b8SBarry Smith       while (ilink->previous) {
1861421e10b8SBarry Smith         ilink = ilink->previous;
18629566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
18639566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
18649566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
1865421e10b8SBarry Smith       }
1866421e10b8SBarry Smith     } else {
1867421e10b8SBarry Smith       while (ilink->next) { /* get to last entry in linked list */
1868421e10b8SBarry Smith         ilink = ilink->next;
1869421e10b8SBarry Smith       }
18709566063dSJacob Faibussowitsch       PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
1871421e10b8SBarry Smith       while (ilink->previous) {
1872421e10b8SBarry Smith         ilink = ilink->previous;
18739566063dSJacob Faibussowitsch         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
18749566063dSJacob Faibussowitsch         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
18759566063dSJacob Faibussowitsch         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
1876421e10b8SBarry Smith       }
1877421e10b8SBarry Smith     }
1878421e10b8SBarry Smith   }
18793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1880421e10b8SBarry Smith }
1881421e10b8SBarry Smith 
1882d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCReset_FieldSplit(PC pc)
1883d71ae5a4SJacob Faibussowitsch {
18840971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
18855a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head, next;
18860971522cSBarry Smith 
18870971522cSBarry Smith   PetscFunctionBegin;
18885a9f2f41SSatish Balay   while (ilink) {
18899566063dSJacob Faibussowitsch     PetscCall(KSPDestroy(&ilink->ksp));
18909566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->x));
18919566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->y));
18929566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&ilink->z));
1893*d484b384SBoris Martin     PetscCall(MatDestroy(&ilink->X));
1894*d484b384SBoris Martin     PetscCall(MatDestroy(&ilink->Y));
18959566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&ilink->sctx));
18969566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is));
18979566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is_col));
18989566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->splitname));
18999566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->fields));
19009566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink->fields_col));
19015a9f2f41SSatish Balay     next = ilink->next;
19029566063dSJacob Faibussowitsch     PetscCall(PetscFree(ilink));
19035a9f2f41SSatish Balay     ilink = next;
19040971522cSBarry Smith   }
1905f5f0d762SBarry Smith   jac->head = NULL;
19069566063dSJacob Faibussowitsch   PetscCall(PetscFree2(jac->x, jac->y));
1907574deadeSBarry Smith   if (jac->mat && jac->mat != jac->pmat) {
19089566063dSJacob Faibussowitsch     PetscCall(MatDestroyMatrices(jac->nsplits, &jac->mat));
1909574deadeSBarry Smith   } else if (jac->mat) {
19100298fd71SBarry Smith     jac->mat = NULL;
1911574deadeSBarry Smith   }
19129566063dSJacob Faibussowitsch   if (jac->pmat) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->pmat));
19139566063dSJacob Faibussowitsch   if (jac->Afield) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->Afield));
1914f5f0d762SBarry Smith   jac->nsplits = 0;
19159566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->w1));
19169566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->w2));
191773716367SStefano Zampini   if (jac->schur) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "AinvB", NULL));
19189566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schur));
19199566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schurp));
19209566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->schur_user));
19219566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->kspschur));
19229566063dSJacob Faibussowitsch   PetscCall(KSPDestroy(&jac->kspupper));
19239566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->B));
19249566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->C));
19259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&jac->H));
19269566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->u));
19279566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->v));
19289566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->Hu));
19299566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&jac->d));
19309566063dSJacob Faibussowitsch   PetscCall(PetscFree(jac->vecz));
19319566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&jac->gkbviewer));
19326dbb499eSCian Wilson   jac->isrestrict = PETSC_FALSE;
19333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1934574deadeSBarry Smith }
1935574deadeSBarry Smith 
1936d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCDestroy_FieldSplit(PC pc)
1937d71ae5a4SJacob Faibussowitsch {
1938574deadeSBarry Smith   PetscFunctionBegin;
19399566063dSJacob Faibussowitsch   PetscCall(PCReset_FieldSplit(pc));
19409566063dSJacob Faibussowitsch   PetscCall(PetscFree(pc->data));
19412e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL));
19429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", NULL));
19439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL));
19449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", NULL));
19459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", NULL));
19462e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", NULL));
19472e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", NULL));
19482e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
19492e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
19502e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
19512e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
19522e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
19539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
19549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
19559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
19562e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
19573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19580971522cSBarry Smith }
19590971522cSBarry Smith 
1960ce78bad3SBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc, PetscOptionItems PetscOptionsObject)
1961d71ae5a4SJacob Faibussowitsch {
19626c924f48SJed Brown   PetscInt        bs;
19637b752e3dSPatrick Sanan   PetscBool       flg;
19649dcbbd2bSBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit *)pc->data;
19653b224e63SBarry Smith   PCCompositeType ctype;
19661b9fc7fcSBarry Smith 
19670971522cSBarry Smith   PetscFunctionBegin;
1968d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "FieldSplit options");
19699566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_fieldsplit_dm_splits", "Whether to use DMCreateFieldDecomposition() for splits", "PCFieldSplitSetDMSplits", jac->dm_splits, &jac->dm_splits, NULL));
19709566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-pc_fieldsplit_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", jac->bs, &bs, &flg));
19711baa6e33SBarry Smith   if (flg) PetscCall(PCFieldSplitSetBlockSize(pc, bs));
19722686e3e9SMatthew G. Knepley   jac->diag_use_amat = pc->useAmat;
19739566063dSJacob 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));
19742686e3e9SMatthew G. Knepley   jac->offdiag_use_amat = pc->useAmat;
19759566063dSJacob 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));
19769566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-pc_fieldsplit_detect_saddle_point", "Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint", jac->detect, &jac->detect, NULL));
19779566063dSJacob Faibussowitsch   PetscCall(PCFieldSplitSetDetectSaddlePoint(pc, jac->detect)); /* Sets split type and Schur PC type */
19789566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-pc_fieldsplit_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&ctype, &flg));
19791baa6e33SBarry Smith   if (flg) PetscCall(PCFieldSplitSetType(pc, ctype));
1980c30613efSMatthew Knepley   /* Only setup fields once */
1981b6555650SPierre Jolivet   if (jac->bs > 0 && jac->nsplits == 0) {
198280670ca5SBarry Smith     /* only allow user to set fields from command line.
1983d32f9abdSBarry Smith        otherwise user can set them in PCFieldSplitSetDefaults() */
19849566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc));
19859566063dSJacob Faibussowitsch     if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n"));
1986d32f9abdSBarry Smith   }
1987c5d2311dSJed Brown   if (jac->type == PC_COMPOSITE_SCHUR) {
19889566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetEnum(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_schur_factorization_type", PCFieldSplitSchurFactTypes, (PetscEnum *)&jac->schurfactorization, &flg));
19899566063dSJacob Faibussowitsch     if (flg) PetscCall(PetscInfo(pc, "Deprecated use of -pc_fieldsplit_schur_factorization_type\n"));
19909566063dSJacob 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));
19919566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_precondition", "How to build preconditioner for Schur complement", "PCFieldSplitSetSchurPre", PCFieldSplitSchurPreTypes, (PetscEnum)jac->schurpre, (PetscEnum *)&jac->schurpre, NULL));
19929566063dSJacob Faibussowitsch     PetscCall(PetscOptionsScalar("-pc_fieldsplit_schur_scale", "Scale Schur complement", "PCFieldSplitSetSchurScale", jac->schurscale, &jac->schurscale, NULL));
1993a51937d4SCarola Kruse   } else if (jac->type == PC_COMPOSITE_GKB) {
1994a077d33dSBarry Smith     PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_tol", "The tolerance for the lower bound stopping criterion", "PCFieldSplitSetGKBTol", jac->gkbtol, &jac->gkbtol, NULL));
1995a077d33dSBarry Smith     PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_delay", "The delay value for lower bound criterion", "PCFieldSplitSetGKBDelay", jac->gkbdelay, &jac->gkbdelay, NULL));
1996a077d33dSBarry Smith     PetscCall(PetscOptionsBoundedReal("-pc_fieldsplit_gkb_nu", "Parameter in augmented Lagrangian approach", "PCFieldSplitSetGKBNu", jac->gkbnu, &jac->gkbnu, NULL, 0.0));
1997a077d33dSBarry Smith     PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_maxit", "Maximum allowed number of iterations", "PCFieldSplitSetGKBMaxit", jac->gkbmaxit, &jac->gkbmaxit, NULL));
19989566063dSJacob Faibussowitsch     PetscCall(PetscOptionsBool("-pc_fieldsplit_gkb_monitor", "Prints number of GKB iterations and error", "PCFieldSplitGKB", jac->gkbmonitor, &jac->gkbmonitor, NULL));
1999c5d2311dSJed Brown   }
200034603f55SBarry Smith   /*
200134603f55SBarry Smith     In the initial call to this routine the sub-solver data structures do not exist so we cannot call KSPSetFromOptions() on them yet.
200234603f55SBarry 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
200334603f55SBarry Smith     is called on the outer solver in case changes were made in the options database
200434603f55SBarry Smith 
200534603f55SBarry 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()
200634603f55SBarry 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.
200734603f55SBarry Smith     Without this extra check test p2p1fetidp_olof_full and others fail with incorrect matrix types.
200834603f55SBarry Smith 
200934603f55SBarry Smith     There could be a negative side effect of calling the KSPSetFromOptions() below.
201034603f55SBarry Smith 
201134603f55SBarry 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
201234603f55SBarry Smith   */
201334603f55SBarry Smith   if (jac->issetup) {
201434603f55SBarry Smith     PC_FieldSplitLink ilink = jac->head;
201534603f55SBarry Smith     if (jac->type == PC_COMPOSITE_SCHUR) {
201634603f55SBarry Smith       if (jac->kspupper && jac->kspupper->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspupper));
201734603f55SBarry Smith       if (jac->kspschur && jac->kspschur->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspschur));
201834603f55SBarry Smith     }
201934603f55SBarry Smith     while (ilink) {
202034603f55SBarry Smith       if (ilink->ksp->totalits > 0) PetscCall(KSPSetFromOptions(ilink->ksp));
202134603f55SBarry Smith       ilink = ilink->next;
202234603f55SBarry Smith     }
202334603f55SBarry Smith   }
2024d0609cedSBarry Smith   PetscOptionsHeadEnd();
20253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20260971522cSBarry Smith }
20270971522cSBarry Smith 
2028d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col)
2029d71ae5a4SJacob Faibussowitsch {
203097bbdb24SBarry Smith   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
20315a9f2f41SSatish Balay   PC_FieldSplitLink ilink, next = jac->head;
203269a612a9SBarry Smith   char              prefix[128];
20335d4c12cdSJungho Lee   PetscInt          i;
2034835f2295SStefano Zampini   PetscLogEvent     nse;
20350971522cSBarry Smith 
20360971522cSBarry Smith   PetscFunctionBegin;
20376c924f48SJed Brown   if (jac->splitdefined) {
20389566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
20393ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
20406c924f48SJed Brown   }
2041ac530a7eSPierre 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]);
20429566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
2043a04f6461SBarry Smith   if (splitname) {
20449566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
2045a04f6461SBarry Smith   } else {
20469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(3, &ilink->splitname));
204763a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ilink->splitname, 2, "%" PetscInt_FMT, jac->nsplits));
2048a04f6461SBarry Smith   }
2049835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(jac->nsplits, &nse));
2050835f2295SStefano Zampini   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */
20519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &ilink->fields));
20529566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ilink->fields, fields, n));
20539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &ilink->fields_col));
20549566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(ilink->fields_col, fields_col, n));
20552fa5cd67SKarl Rupp 
20565a9f2f41SSatish Balay   ilink->nfields = n;
20570298fd71SBarry Smith   ilink->next    = NULL;
20589566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
20593821be0aSBarry Smith   PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel));
20609566063dSJacob Faibussowitsch   PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
20619566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
20629566063dSJacob Faibussowitsch   PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
206369a612a9SBarry Smith 
20649566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
20659566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
20660971522cSBarry Smith 
20670971522cSBarry Smith   if (!next) {
20685a9f2f41SSatish Balay     jac->head       = ilink;
20690298fd71SBarry Smith     ilink->previous = NULL;
20700971522cSBarry Smith   } else {
2071ad540459SPierre Jolivet     while (next->next) next = next->next;
20725a9f2f41SSatish Balay     next->next      = ilink;
207351f519a2SBarry Smith     ilink->previous = next;
20740971522cSBarry Smith   }
20750971522cSBarry Smith   jac->nsplits++;
20763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20770971522cSBarry Smith }
20780971522cSBarry Smith 
2079d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp)
2080d71ae5a4SJacob Faibussowitsch {
2081285fb4e2SStefano Zampini   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2082285fb4e2SStefano Zampini 
2083285fb4e2SStefano Zampini   PetscFunctionBegin;
2084285fb4e2SStefano Zampini   *subksp = NULL;
2085285fb4e2SStefano Zampini   if (n) *n = 0;
2086285fb4e2SStefano Zampini   if (jac->type == PC_COMPOSITE_SCHUR) {
2087285fb4e2SStefano Zampini     PetscInt nn;
2088285fb4e2SStefano Zampini 
208928b400f6SJacob Faibussowitsch     PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()");
209063a3b9bcSJacob Faibussowitsch     PetscCheck(jac->nsplits == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unexpected number of splits %" PetscInt_FMT " != 2", jac->nsplits);
2091285fb4e2SStefano Zampini     nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0);
20929566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nn, subksp));
2093285fb4e2SStefano Zampini     (*subksp)[0] = jac->head->ksp;
2094285fb4e2SStefano Zampini     (*subksp)[1] = jac->kspschur;
2095285fb4e2SStefano Zampini     if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper;
2096285fb4e2SStefano Zampini     if (n) *n = nn;
2097285fb4e2SStefano Zampini   }
20983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2099285fb4e2SStefano Zampini }
2100285fb4e2SStefano Zampini 
2101d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc, PetscInt *n, KSP **subksp)
2102d71ae5a4SJacob Faibussowitsch {
2103e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2104e69d4d44SBarry Smith 
2105e69d4d44SBarry Smith   PetscFunctionBegin;
210628b400f6SJacob Faibussowitsch   PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()");
21079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(jac->nsplits, subksp));
21089566063dSJacob Faibussowitsch   PetscCall(MatSchurComplementGetKSP(jac->schur, *subksp));
21092fa5cd67SKarl Rupp 
2110e69d4d44SBarry Smith   (*subksp)[1] = jac->kspschur;
211113e0d083SBarry Smith   if (n) *n = jac->nsplits;
21123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2113e69d4d44SBarry Smith }
21140971522cSBarry Smith 
2115d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp)
2116d71ae5a4SJacob Faibussowitsch {
21170971522cSBarry Smith   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
21180971522cSBarry Smith   PetscInt          cnt   = 0;
21195a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
21200971522cSBarry Smith 
21210971522cSBarry Smith   PetscFunctionBegin;
21229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(jac->nsplits, subksp));
21235a9f2f41SSatish Balay   while (ilink) {
21245a9f2f41SSatish Balay     (*subksp)[cnt++] = ilink->ksp;
21255a9f2f41SSatish Balay     ilink            = ilink->next;
21260971522cSBarry Smith   }
212763a3b9bcSJacob 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);
212813e0d083SBarry Smith   if (n) *n = jac->nsplits;
21293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21300971522cSBarry Smith }
21310971522cSBarry Smith 
2132cc4c1da9SBarry Smith /*@
2133f1580f4eSBarry Smith   PCFieldSplitRestrictIS - Restricts the fieldsplit `IS`s to be within a given `IS`.
21346dbb499eSCian Wilson 
21356dbb499eSCian Wilson   Input Parameters:
21366dbb499eSCian Wilson + pc  - the preconditioner context
2137feefa0e1SJacob Faibussowitsch - isy - the index set that defines the indices to which the fieldsplit is to be restricted
21386dbb499eSCian Wilson 
21396dbb499eSCian Wilson   Level: advanced
21406dbb499eSCian Wilson 
2141feefa0e1SJacob Faibussowitsch   Developer Notes:
2142f1580f4eSBarry Smith   It seems the resulting `IS`s will not cover the entire space, so
2143f1580f4eSBarry Smith   how can they define a convergent preconditioner? Needs explaining.
2144f1580f4eSBarry Smith 
214560f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
21466dbb499eSCian Wilson @*/
2147d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitRestrictIS(PC pc, IS isy)
2148d71ae5a4SJacob Faibussowitsch {
21496dbb499eSCian Wilson   PetscFunctionBegin;
21506dbb499eSCian Wilson   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
21516dbb499eSCian Wilson   PetscValidHeaderSpecific(isy, IS_CLASSID, 2);
2152cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitRestrictIS_C", (PC, IS), (pc, isy));
21533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21546dbb499eSCian Wilson }
21556dbb499eSCian Wilson 
2156d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy)
2157d71ae5a4SJacob Faibussowitsch {
21586dbb499eSCian Wilson   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
21596dbb499eSCian Wilson   PC_FieldSplitLink ilink = jac->head, next;
21606dbb499eSCian Wilson   PetscInt          localsize, size, sizez, i;
21616dbb499eSCian Wilson   const PetscInt   *ind, *indz;
21626dbb499eSCian Wilson   PetscInt         *indc, *indcz;
21636dbb499eSCian Wilson   PetscBool         flg;
21646dbb499eSCian Wilson 
21656dbb499eSCian Wilson   PetscFunctionBegin;
21669566063dSJacob Faibussowitsch   PetscCall(ISGetLocalSize(isy, &localsize));
21679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Scan(&localsize, &size, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)isy)));
21686dbb499eSCian Wilson   size -= localsize;
21696dbb499eSCian Wilson   while (ilink) {
21706dbb499eSCian Wilson     IS isrl, isr;
21711c7cfba8SBarry Smith     PC subpc;
21729566063dSJacob Faibussowitsch     PetscCall(ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl));
21739566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(isrl, &localsize));
21749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(localsize, &indc));
21759566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(isrl, &ind));
21769566063dSJacob Faibussowitsch     PetscCall(PetscArraycpy(indc, ind, localsize));
21779566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(isrl, &ind));
21789566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&isrl));
21796dbb499eSCian Wilson     for (i = 0; i < localsize; i++) *(indc + i) += size;
21809566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)isy), localsize, indc, PETSC_OWN_POINTER, &isr));
21819566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isr));
21829566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is));
21836dbb499eSCian Wilson     ilink->is = isr;
21849566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)isr));
21859566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&ilink->is_col));
21866dbb499eSCian Wilson     ilink->is_col = isr;
21879566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&isr));
21889566063dSJacob Faibussowitsch     PetscCall(KSPGetPC(ilink->ksp, &subpc));
21899566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)subpc, PCFIELDSPLIT, &flg));
21906dbb499eSCian Wilson     if (flg) {
21916dbb499eSCian Wilson       IS       iszl, isz;
21926dbb499eSCian Wilson       MPI_Comm comm;
21939566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(ilink->is, &localsize));
21946dbb499eSCian Wilson       comm = PetscObjectComm((PetscObject)ilink->is);
21959566063dSJacob Faibussowitsch       PetscCall(ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl));
21969566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Scan(&localsize, &sizez, 1, MPIU_INT, MPI_SUM, comm));
21976dbb499eSCian Wilson       sizez -= localsize;
21989566063dSJacob Faibussowitsch       PetscCall(ISGetLocalSize(iszl, &localsize));
21999566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(localsize, &indcz));
22009566063dSJacob Faibussowitsch       PetscCall(ISGetIndices(iszl, &indz));
22019566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(indcz, indz, localsize));
22029566063dSJacob Faibussowitsch       PetscCall(ISRestoreIndices(iszl, &indz));
22039566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&iszl));
22046dbb499eSCian Wilson       for (i = 0; i < localsize; i++) *(indcz + i) += sizez;
22059566063dSJacob Faibussowitsch       PetscCall(ISCreateGeneral(comm, localsize, indcz, PETSC_OWN_POINTER, &isz));
22069566063dSJacob Faibussowitsch       PetscCall(PCFieldSplitRestrictIS(subpc, isz));
22079566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&isz));
22086dbb499eSCian Wilson     }
22096dbb499eSCian Wilson     next  = ilink->next;
22106dbb499eSCian Wilson     ilink = next;
22116dbb499eSCian Wilson   }
22126dbb499eSCian Wilson   jac->isrestrict = PETSC_TRUE;
22133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22146dbb499eSCian Wilson }
22156dbb499eSCian Wilson 
2216d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc, const char splitname[], IS is)
2217d71ae5a4SJacob Faibussowitsch {
2218704ba839SBarry Smith   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
2219704ba839SBarry Smith   PC_FieldSplitLink ilink, next = jac->head;
2220704ba839SBarry Smith   char              prefix[128];
2221835f2295SStefano Zampini   PetscLogEvent     nse;
2222704ba839SBarry Smith 
2223704ba839SBarry Smith   PetscFunctionBegin;
22246c924f48SJed Brown   if (jac->splitdefined) {
22259566063dSJacob Faibussowitsch     PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
22263ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
22276c924f48SJed Brown   }
22289566063dSJacob Faibussowitsch   PetscCall(PetscNew(&ilink));
2229a04f6461SBarry Smith   if (splitname) {
22309566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
2231a04f6461SBarry Smith   } else {
22329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(8, &ilink->splitname));
223363a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(ilink->splitname, 7, "%" PetscInt_FMT, jac->nsplits));
2234a04f6461SBarry Smith   }
2235835f2295SStefano Zampini   PetscCall(PetscMPIIntCast(jac->nsplits, &nse));
2236835f2295SStefano Zampini   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + nse : KSP_Solve_FS_0 + 4; /* Splits greater than 4 logged in 4th split */
22379566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)is));
22389566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ilink->is));
2239b5787286SJed Brown   ilink->is = is;
22409566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)is));
22419566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&ilink->is_col));
2242b5787286SJed Brown   ilink->is_col = is;
22430298fd71SBarry Smith   ilink->next   = NULL;
22449566063dSJacob Faibussowitsch   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
22453821be0aSBarry Smith   PetscCall(KSPSetNestLevel(ilink->ksp, pc->kspnestlevel));
22469566063dSJacob Faibussowitsch   PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
22479566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
22489566063dSJacob Faibussowitsch   PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
2249704ba839SBarry Smith 
22509566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
22519566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
2252704ba839SBarry Smith 
2253704ba839SBarry Smith   if (!next) {
2254704ba839SBarry Smith     jac->head       = ilink;
22550298fd71SBarry Smith     ilink->previous = NULL;
2256704ba839SBarry Smith   } else {
2257ad540459SPierre Jolivet     while (next->next) next = next->next;
2258704ba839SBarry Smith     next->next      = ilink;
2259704ba839SBarry Smith     ilink->previous = next;
2260704ba839SBarry Smith   }
2261704ba839SBarry Smith   jac->nsplits++;
22623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2263704ba839SBarry Smith }
2264704ba839SBarry Smith 
22655d83a8b1SBarry Smith /*@
226660f59c3bSBarry Smith   PCFieldSplitSetFields - Sets the fields that define one particular split in `PCFIELDSPLIT`
22670971522cSBarry Smith 
2268c3339decSBarry Smith   Logically Collective
22690971522cSBarry Smith 
22700971522cSBarry Smith   Input Parameters:
22710971522cSBarry Smith + pc         - the preconditioner context
227260f59c3bSBarry Smith . splitname  - name of this split, if `NULL` the number of the split is used
22730971522cSBarry Smith . n          - the number of fields in this split
22743b374dbdSBarry Smith . fields     - the fields in this split
227580670ca5SBarry 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
227680670ca5SBarry Smith                of the matrix and `fields_col` provides the column indices for that block
227780670ca5SBarry Smith 
227880670ca5SBarry Smith   Options Database Key:
227980670ca5SBarry Smith . -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split
22800971522cSBarry Smith 
22810971522cSBarry Smith   Level: intermediate
22820971522cSBarry Smith 
228395452b02SPatrick Sanan   Notes:
2284f1580f4eSBarry Smith   Use `PCFieldSplitSetIS()` to set a  general set of indices as a split.
2285d32f9abdSBarry Smith 
228680670ca5SBarry Smith   If the matrix used to construct the preconditioner is `MATNEST` then field i refers to the `is_row[i]` `IS` passed to `MatCreateNest()`.
228780670ca5SBarry Smith 
228880670ca5SBarry Smith   If the matrix used to construct the preconditioner is not `MATNEST` then
228954c05997SPierre Jolivet   `PCFieldSplitSetFields()` is for defining fields as strided blocks (based on the block size provided to the matrix with `MatSetBlockSize()` or
229080670ca5SBarry Smith   to the `PC` with `PCFieldSplitSetBlockSize()`). For example, if the block
2291f1580f4eSBarry 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
229214c74629SNuno Nobre   0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x23x56x8.. x12x45x78x....
2293f1580f4eSBarry Smith   where the numbered entries indicate what is in the split.
2294d32f9abdSBarry Smith 
2295db4c96c1SJed Brown   This function is called once per split (it creates a new split each time).  Solve options
229660f59c3bSBarry Smith   for this split will be available under the prefix `-fieldsplit_SPLITNAME_`.
2297db4c96c1SJed Brown 
229880670ca5SBarry Smith   `PCFieldSplitSetIS()` does not support having a `fields_col` different from `fields`
22993b374dbdSBarry Smith 
2300feefa0e1SJacob Faibussowitsch   Developer Notes:
2301f1580f4eSBarry Smith   This routine does not actually create the `IS` representing the split, that is delayed
2302f1580f4eSBarry Smith   until `PCSetUp_FieldSplit()`, because information about the vector/matrix layouts may not be
23035d4c12cdSJungho Lee   available when this routine is called.
23045d4c12cdSJungho Lee 
230580670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetIS()`, `PCFieldSplitRestrictIS()`,
230654c05997SPierre Jolivet           `MatSetBlockSize()`, `MatCreateNest()`
23070971522cSBarry Smith @*/
2308cc4c1da9SBarry Smith PetscErrorCode PCFieldSplitSetFields(PC pc, const char splitname[], PetscInt n, const PetscInt fields[], const PetscInt fields_col[])
2309d71ae5a4SJacob Faibussowitsch {
23100971522cSBarry Smith   PetscFunctionBegin;
23110700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
23124f572ea9SToby Isaac   PetscAssertPointer(splitname, 2);
231363a3b9bcSJacob Faibussowitsch   PetscCheck(n >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, splitname);
23144f572ea9SToby Isaac   PetscAssertPointer(fields, 4);
2315cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetFields_C", (PC, const char[], PetscInt, const PetscInt *, const PetscInt *), (pc, splitname, n, fields, fields_col));
23163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23170971522cSBarry Smith }
23180971522cSBarry Smith 
2319c84da90fSDmitry Karpeev /*@
2320f1580f4eSBarry Smith   PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build
2321c14e9f00SDavid Andrs   the sub-matrices associated with each split. Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2322c84da90fSDmitry Karpeev 
2323c3339decSBarry Smith   Logically Collective
2324c84da90fSDmitry Karpeev 
2325c84da90fSDmitry Karpeev   Input Parameters:
2326c84da90fSDmitry Karpeev + pc  - the preconditioner object
2327c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
2328c84da90fSDmitry Karpeev 
232920f4b53cSBarry Smith   Options Database Key:
2330147403d9SBarry Smith . -pc_fieldsplit_diag_use_amat - use the Amat to provide the diagonal blocks
2331c84da90fSDmitry Karpeev 
2332c84da90fSDmitry Karpeev   Level: intermediate
2333c84da90fSDmitry Karpeev 
233460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetDiagUseAmat()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFIELDSPLIT`
2335c84da90fSDmitry Karpeev @*/
2336d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc, PetscBool flg)
2337d71ae5a4SJacob Faibussowitsch {
2338c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2339c84da90fSDmitry Karpeev   PetscBool      isfs;
2340c84da90fSDmitry Karpeev 
2341c84da90fSDmitry Karpeev   PetscFunctionBegin;
2342c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
23439566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
234428b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2345c84da90fSDmitry Karpeev   jac->diag_use_amat = flg;
23463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2347c84da90fSDmitry Karpeev }
2348c84da90fSDmitry Karpeev 
2349c84da90fSDmitry Karpeev /*@
2350f1580f4eSBarry Smith   PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) to build
2351c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2352c84da90fSDmitry Karpeev 
2353c3339decSBarry Smith   Logically Collective
2354c84da90fSDmitry Karpeev 
235520f4b53cSBarry Smith   Input Parameter:
2356c84da90fSDmitry Karpeev . pc - the preconditioner object
2357c84da90fSDmitry Karpeev 
235820f4b53cSBarry Smith   Output Parameter:
2359c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
2360c84da90fSDmitry Karpeev 
2361c84da90fSDmitry Karpeev   Level: intermediate
2362c84da90fSDmitry Karpeev 
236360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetDiagUseAmat()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFIELDSPLIT`
2364c84da90fSDmitry Karpeev @*/
2365d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc, PetscBool *flg)
2366d71ae5a4SJacob Faibussowitsch {
2367c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2368c84da90fSDmitry Karpeev   PetscBool      isfs;
2369c84da90fSDmitry Karpeev 
2370c84da90fSDmitry Karpeev   PetscFunctionBegin;
2371c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
23724f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
23739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
237428b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2375c84da90fSDmitry Karpeev   *flg = jac->diag_use_amat;
23763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2377c84da90fSDmitry Karpeev }
2378c84da90fSDmitry Karpeev 
2379c84da90fSDmitry Karpeev /*@
2380f1580f4eSBarry Smith   PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build
2381c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2382c84da90fSDmitry Karpeev 
2383c3339decSBarry Smith   Logically Collective
2384c84da90fSDmitry Karpeev 
2385c84da90fSDmitry Karpeev   Input Parameters:
2386c84da90fSDmitry Karpeev + pc  - the preconditioner object
2387c84da90fSDmitry Karpeev - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
2388c84da90fSDmitry Karpeev 
238920f4b53cSBarry Smith   Options Database Key:
2390147403d9SBarry Smith . -pc_fieldsplit_off_diag_use_amat <bool> - use the Amat to extract the off-diagonal blocks
2391c84da90fSDmitry Karpeev 
2392c84da90fSDmitry Karpeev   Level: intermediate
2393c84da90fSDmitry Karpeev 
239460f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFieldSplitSetDiagUseAmat()`, `PCFIELDSPLIT`
2395c84da90fSDmitry Karpeev @*/
2396d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc, PetscBool flg)
2397d71ae5a4SJacob Faibussowitsch {
2398c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2399c84da90fSDmitry Karpeev   PetscBool      isfs;
2400c84da90fSDmitry Karpeev 
2401c84da90fSDmitry Karpeev   PetscFunctionBegin;
2402c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
24039566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
240428b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2405c84da90fSDmitry Karpeev   jac->offdiag_use_amat = flg;
24063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2407c84da90fSDmitry Karpeev }
2408c84da90fSDmitry Karpeev 
2409c84da90fSDmitry Karpeev /*@
2410f1580f4eSBarry Smith   PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) to build
2411c14e9f00SDavid Andrs   the sub-matrices associated with each split.  Where `KSPSetOperators`(ksp,Amat,Pmat) was used to supply the operators.
2412c84da90fSDmitry Karpeev 
2413c3339decSBarry Smith   Logically Collective
2414c84da90fSDmitry Karpeev 
241520f4b53cSBarry Smith   Input Parameter:
2416c84da90fSDmitry Karpeev . pc - the preconditioner object
2417c84da90fSDmitry Karpeev 
241820f4b53cSBarry Smith   Output Parameter:
2419c84da90fSDmitry Karpeev . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
2420c84da90fSDmitry Karpeev 
2421c84da90fSDmitry Karpeev   Level: intermediate
2422c84da90fSDmitry Karpeev 
242360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCSetOperators()`, `KSPSetOperators()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFieldSplitGetDiagUseAmat()`, `PCFIELDSPLIT`
2424c84da90fSDmitry Karpeev @*/
2425d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc, PetscBool *flg)
2426d71ae5a4SJacob Faibussowitsch {
2427c84da90fSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2428c84da90fSDmitry Karpeev   PetscBool      isfs;
2429c84da90fSDmitry Karpeev 
2430c84da90fSDmitry Karpeev   PetscFunctionBegin;
2431c84da90fSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
24324f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
24339566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
243428b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
2435c84da90fSDmitry Karpeev   *flg = jac->offdiag_use_amat;
24363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2437c84da90fSDmitry Karpeev }
2438c84da90fSDmitry Karpeev 
2439cc4c1da9SBarry Smith /*@
2440f1580f4eSBarry Smith   PCFieldSplitSetIS - Sets the exact elements for a split in a `PCFIELDSPLIT`
2441704ba839SBarry Smith 
2442c3339decSBarry Smith   Logically Collective
2443704ba839SBarry Smith 
2444704ba839SBarry Smith   Input Parameters:
2445704ba839SBarry Smith + pc        - the preconditioner context
244660f59c3bSBarry Smith . splitname - name of this split, if `NULL` the number of the split is used
2447f1580f4eSBarry Smith - is        - the index set that defines the elements in this split
2448704ba839SBarry Smith 
244960f59c3bSBarry Smith   Level: intermediate
245060f59c3bSBarry Smith 
2451a6ffb8dbSJed Brown   Notes:
245280670ca5SBarry Smith   Use `PCFieldSplitSetFields()`, for splits defined by strided `IS` based on the matrix block size or the `is_rows[]` passed into `MATNEST`
2453a6ffb8dbSJed Brown 
2454db4c96c1SJed Brown   This function is called once per split (it creates a new split each time).  Solve options
2455db4c96c1SJed Brown   for this split will be available under the prefix -fieldsplit_SPLITNAME_.
2456d32f9abdSBarry Smith 
245780670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetFields()`
2458704ba839SBarry Smith @*/
2459d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetIS(PC pc, const char splitname[], IS is)
2460d71ae5a4SJacob Faibussowitsch {
2461704ba839SBarry Smith   PetscFunctionBegin;
24620700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
24634f572ea9SToby Isaac   if (splitname) PetscAssertPointer(splitname, 2);
2464db4c96c1SJed Brown   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
2465cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetIS_C", (PC, const char[], IS), (pc, splitname, is));
24663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2467704ba839SBarry Smith }
2468704ba839SBarry Smith 
2469cc4c1da9SBarry Smith /*@
2470f1580f4eSBarry Smith   PCFieldSplitGetIS - Retrieves the elements for a split as an `IS`
247157a9adfeSMatthew G Knepley 
2472c3339decSBarry Smith   Logically Collective
247357a9adfeSMatthew G Knepley 
247457a9adfeSMatthew G Knepley   Input Parameters:
247557a9adfeSMatthew G Knepley + pc        - the preconditioner context
247657a9adfeSMatthew G Knepley - splitname - name of this split
247757a9adfeSMatthew G Knepley 
247857a9adfeSMatthew G Knepley   Output Parameter:
2479feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split, or `NULL` if the split is not found
248057a9adfeSMatthew G Knepley 
248157a9adfeSMatthew G Knepley   Level: intermediate
248257a9adfeSMatthew G Knepley 
248380670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetIS()`, `PCFieldSplitGetISByIndex()`
248457a9adfeSMatthew G Knepley @*/
2485d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetIS(PC pc, const char splitname[], IS *is)
2486d71ae5a4SJacob Faibussowitsch {
248757a9adfeSMatthew G Knepley   PetscFunctionBegin;
248857a9adfeSMatthew G Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
24894f572ea9SToby Isaac   PetscAssertPointer(splitname, 2);
24904f572ea9SToby Isaac   PetscAssertPointer(is, 3);
249157a9adfeSMatthew G Knepley   {
249257a9adfeSMatthew G Knepley     PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
249357a9adfeSMatthew G Knepley     PC_FieldSplitLink ilink = jac->head;
249457a9adfeSMatthew G Knepley     PetscBool         found;
249557a9adfeSMatthew G Knepley 
24960298fd71SBarry Smith     *is = NULL;
249757a9adfeSMatthew G Knepley     while (ilink) {
24989566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(ilink->splitname, splitname, &found));
249957a9adfeSMatthew G Knepley       if (found) {
250057a9adfeSMatthew G Knepley         *is = ilink->is;
250157a9adfeSMatthew G Knepley         break;
250257a9adfeSMatthew G Knepley       }
250357a9adfeSMatthew G Knepley       ilink = ilink->next;
250457a9adfeSMatthew G Knepley     }
250557a9adfeSMatthew G Knepley   }
25063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
250757a9adfeSMatthew G Knepley }
250857a9adfeSMatthew G Knepley 
2509cc4c1da9SBarry Smith /*@
2510f1580f4eSBarry Smith   PCFieldSplitGetISByIndex - Retrieves the elements for a given split as an `IS`
2511998f007dSPierre Jolivet 
2512c3339decSBarry Smith   Logically Collective
2513998f007dSPierre Jolivet 
2514998f007dSPierre Jolivet   Input Parameters:
2515998f007dSPierre Jolivet + pc    - the preconditioner context
2516998f007dSPierre Jolivet - index - index of this split
2517998f007dSPierre Jolivet 
2518998f007dSPierre Jolivet   Output Parameter:
2519feefa0e1SJacob Faibussowitsch . is - the index set that defines the elements in this split
2520998f007dSPierre Jolivet 
2521998f007dSPierre Jolivet   Level: intermediate
2522998f007dSPierre Jolivet 
252380670ca5SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitGetIS()`, `PCFieldSplitSetIS()`,
252480670ca5SBarry Smith 
2525998f007dSPierre Jolivet @*/
2526d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetISByIndex(PC pc, PetscInt index, IS *is)
2527d71ae5a4SJacob Faibussowitsch {
2528998f007dSPierre Jolivet   PetscFunctionBegin;
252963a3b9bcSJacob Faibussowitsch   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", index);
2530998f007dSPierre Jolivet   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
25314f572ea9SToby Isaac   PetscAssertPointer(is, 3);
2532998f007dSPierre Jolivet   {
2533998f007dSPierre Jolivet     PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
2534998f007dSPierre Jolivet     PC_FieldSplitLink ilink = jac->head;
2535998f007dSPierre Jolivet     PetscInt          i     = 0;
253663a3b9bcSJacob Faibussowitsch     PetscCheck(index < jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", index, jac->nsplits);
2537998f007dSPierre Jolivet 
2538998f007dSPierre Jolivet     while (i < index) {
2539998f007dSPierre Jolivet       ilink = ilink->next;
2540998f007dSPierre Jolivet       ++i;
2541998f007dSPierre Jolivet     }
25429566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitGetIS(pc, ilink->splitname, is));
2543998f007dSPierre Jolivet   }
25443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2545998f007dSPierre Jolivet }
2546998f007dSPierre Jolivet 
254751f519a2SBarry Smith /*@
254851f519a2SBarry Smith   PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
254980670ca5SBarry Smith   fieldsplit preconditioner when calling `PCFieldSplitSetFields()`. If not set the matrix block size is used.
255051f519a2SBarry Smith 
2551c3339decSBarry Smith   Logically Collective
255251f519a2SBarry Smith 
255351f519a2SBarry Smith   Input Parameters:
255451f519a2SBarry Smith + pc - the preconditioner context
255551f519a2SBarry Smith - bs - the block size
255651f519a2SBarry Smith 
255751f519a2SBarry Smith   Level: intermediate
255851f519a2SBarry Smith 
255980670ca5SBarry Smith   Note:
256080670ca5SBarry Smith   If the matrix is a `MATNEST` then the `is_rows[]` passed to `MatCreateNest()` determines the fields.
256180670ca5SBarry Smith 
256260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
256351f519a2SBarry Smith @*/
2564d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetBlockSize(PC pc, PetscInt bs)
2565d71ae5a4SJacob Faibussowitsch {
256651f519a2SBarry Smith   PetscFunctionBegin;
25670700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2568c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc, bs, 2);
2569cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetBlockSize_C", (PC, PetscInt), (pc, bs));
25703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
257151f519a2SBarry Smith }
257251f519a2SBarry Smith 
25730971522cSBarry Smith /*@C
2574f1580f4eSBarry Smith   PCFieldSplitGetSubKSP - Gets the `KSP` contexts for all splits
25750971522cSBarry Smith 
2576c3339decSBarry Smith   Collective
25770971522cSBarry Smith 
25780971522cSBarry Smith   Input Parameter:
25790971522cSBarry Smith . pc - the preconditioner context
25800971522cSBarry Smith 
25810971522cSBarry Smith   Output Parameters:
258213e0d083SBarry Smith + n      - the number of splits
2583f1580f4eSBarry Smith - subksp - the array of `KSP` contexts
2584196cc216SBarry Smith 
25850971522cSBarry Smith   Level: advanced
25860971522cSBarry Smith 
2587f1580f4eSBarry Smith   Notes:
2588f1580f4eSBarry Smith   After `PCFieldSplitGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()`
2589f1580f4eSBarry Smith   (not the `KSP`, just the array that contains them).
2590f1580f4eSBarry Smith 
2591f1580f4eSBarry Smith   You must call `PCSetUp()` before calling `PCFieldSplitGetSubKSP()`.
2592f1580f4eSBarry Smith 
2593f1580f4eSBarry Smith   If the fieldsplit is of type `PC_COMPOSITE_SCHUR`, it returns the `KSP` object used inside the
2594f1580f4eSBarry Smith   Schur complement and the `KSP` object used to iterate over the Schur complement.
2595f1580f4eSBarry Smith   To access all the `KSP` objects used in `PC_COMPOSITE_SCHUR`, use `PCFieldSplitSchurGetSubKSP()`.
2596f1580f4eSBarry Smith 
2597f1580f4eSBarry Smith   If the fieldsplit is of type `PC_COMPOSITE_GKB`, it returns the `KSP` object used to solve the
2598f1580f4eSBarry Smith   inner linear system defined by the matrix H in each loop.
2599f1580f4eSBarry Smith 
2600feaf08eaSBarry Smith   Fortran Note:
2601e41f517fSBarry Smith   Call `PCFieldSplitRestoreSubKSP()` when the array of `KSP` is no longer needed
2602f1580f4eSBarry Smith 
2603feefa0e1SJacob Faibussowitsch   Developer Notes:
2604f1580f4eSBarry Smith   There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()`
2605f1580f4eSBarry Smith 
260660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitSchurGetSubKSP()`
26070971522cSBarry Smith @*/
2608d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSubKSP(PC pc, PetscInt *n, KSP *subksp[])
2609d71ae5a4SJacob Faibussowitsch {
26100971522cSBarry Smith   PetscFunctionBegin;
26110700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26124f572ea9SToby Isaac   if (n) PetscAssertPointer(n, 2);
2613cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
26143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
26150971522cSBarry Smith }
26160971522cSBarry Smith 
2617285fb4e2SStefano Zampini /*@C
2618f1580f4eSBarry Smith   PCFieldSplitSchurGetSubKSP - Gets the `KSP` contexts used inside the Schur complement based `PCFIELDSPLIT`
2619285fb4e2SStefano Zampini 
262060f59c3bSBarry Smith   Collective
2621285fb4e2SStefano Zampini 
2622285fb4e2SStefano Zampini   Input Parameter:
2623285fb4e2SStefano Zampini . pc - the preconditioner context
2624285fb4e2SStefano Zampini 
2625285fb4e2SStefano Zampini   Output Parameters:
2626285fb4e2SStefano Zampini + n      - the number of splits
2627f1580f4eSBarry Smith - subksp - the array of `KSP` contexts
2628285fb4e2SStefano Zampini 
2629285fb4e2SStefano Zampini   Level: advanced
2630285fb4e2SStefano Zampini 
2631f1580f4eSBarry Smith   Notes:
2632f1580f4eSBarry Smith   After `PCFieldSplitSchurGetSubKSP()` the array of `KSP`s is to be freed by the user with `PetscFree()`
2633f1580f4eSBarry Smith   (not the `KSP` just the array that contains them).
2634f1580f4eSBarry Smith 
2635f1580f4eSBarry Smith   You must call `PCSetUp()` before calling `PCFieldSplitSchurGetSubKSP()`.
2636f1580f4eSBarry Smith 
2637f1580f4eSBarry Smith   If the fieldsplit type is of type `PC_COMPOSITE_SCHUR`, it returns (in order)
2638f1580f4eSBarry Smith +  1  - the `KSP` used for the (1,1) block
2639f1580f4eSBarry Smith .  2  - the `KSP` used for the Schur complement (not the one used for the interior Schur solver)
2640f1580f4eSBarry Smith -  3  - the `KSP` used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block).
2641f1580f4eSBarry Smith 
2642f1580f4eSBarry Smith   It returns a null array if the fieldsplit is not of type `PC_COMPOSITE_SCHUR`; in this case, you should use `PCFieldSplitGetSubKSP()`.
2643f1580f4eSBarry Smith 
2644feaf08eaSBarry Smith   Fortran Note:
2645e41f517fSBarry Smith   Call `PCFieldSplitSchurRestoreSubKSP()` when the array of `KSP` is no longer needed
2646f1580f4eSBarry Smith 
2647f1580f4eSBarry Smith   Developer Notes:
2648f1580f4eSBarry Smith   There should be a `PCFieldSplitRestoreSubKSP()` instead of requiring the user to call `PetscFree()`
2649f1580f4eSBarry Smith 
2650f1580f4eSBarry Smith   Should the functionality of `PCFieldSplitSchurGetSubKSP()` and `PCFieldSplitGetSubKSP()` be merged?
2651f1580f4eSBarry Smith 
265260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`, `PCFieldSplitGetSubKSP()`
2653285fb4e2SStefano Zampini @*/
2654d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc, PetscInt *n, KSP *subksp[])
2655d71ae5a4SJacob Faibussowitsch {
2656285fb4e2SStefano Zampini   PetscFunctionBegin;
2657285fb4e2SStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
26584f572ea9SToby Isaac   if (n) PetscAssertPointer(n, 2);
2659cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitSchurGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
26603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2661285fb4e2SStefano Zampini }
2662285fb4e2SStefano Zampini 
2663e69d4d44SBarry Smith /*@
2664c14e9f00SDavid Andrs   PCFieldSplitSetSchurPre -  Indicates from what operator the preconditioner is constructed for the Schur complement.
2665a1e3cbf9SBarry Smith   The default is the A11 matrix.
2666e69d4d44SBarry Smith 
2667c3339decSBarry Smith   Collective
2668e69d4d44SBarry Smith 
2669e69d4d44SBarry Smith   Input Parameters:
2670e69d4d44SBarry Smith + pc    - the preconditioner context
2671f1580f4eSBarry Smith . ptype - which matrix to use for preconditioning the Schur complement: `PC_FIELDSPLIT_SCHUR_PRE_A11` (default),
2672f1580f4eSBarry Smith               `PC_FIELDSPLIT_SCHUR_PRE_SELF`, `PC_FIELDSPLIT_SCHUR_PRE_USER`,
2673f1580f4eSBarry Smith               `PC_FIELDSPLIT_SCHUR_PRE_SELFP`, and `PC_FIELDSPLIT_SCHUR_PRE_FULL`
267460f59c3bSBarry Smith - pre   - matrix to use for preconditioning, or `NULL`
2675084e4875SJed Brown 
2676f1580f4eSBarry Smith   Options Database Keys:
2677d59693daSPierre Jolivet + -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is `a11`. See notes for meaning of various arguments
2678a1e3cbf9SBarry Smith - -fieldsplit_1_pc_type <pctype>                               - the preconditioner algorithm that is used to construct the preconditioner from the operator
2679e69d4d44SBarry Smith 
268060f59c3bSBarry Smith   Level: intermediate
268160f59c3bSBarry Smith 
2682fd1303e9SJungho Lee   Notes:
2683f1580f4eSBarry Smith   If ptype is
2684f1580f4eSBarry Smith +     a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner
2685f1580f4eSBarry Smith   matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix
2686f1580f4eSBarry Smith .     self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix:
2687e7593814SPierre Jolivet   The only preconditioners that currently work with this symbolic representation matrix object are `PCLSC` and `PCHPDDM`
2688f1580f4eSBarry Smith .     user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument
2689f1580f4eSBarry Smith   to this function).
2690a077d33dSBarry Smith .     selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation $ Sp = A11 - A10 inv(diag(A00)) A01 $
2691f1580f4eSBarry Smith   This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be
2692d59693daSPierre Jolivet   lumped before extracting the diagonal using the additional option `-fieldsplit_1_mat_schur_complement_ainv_type lump`
2693f1580f4eSBarry Smith -     full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation
2694f1580f4eSBarry Smith   computed internally by `PCFIELDSPLIT` (this is expensive)
2695f1580f4eSBarry Smith   useful mostly as a test that the Schur complement approach can work for your problem
2696fd1303e9SJungho Lee 
2697d59693daSPierre Jolivet   When solving a saddle point problem, where the A11 block is identically zero, using `a11` as the ptype only makes sense
2698a077d33dSBarry Smith   with the additional option `-fieldsplit_1_pc_type none`. Usually for saddle point problems one would use a `ptype` of `self` and
2699d59693daSPierre Jolivet   `-fieldsplit_1_pc_type lsc` which uses the least squares commutator to compute a preconditioner for the Schur complement.
2700fd1303e9SJungho Lee 
2701a077d33dSBarry Smith   Developer Note:
2702a077d33dSBarry Smith   The name of this function and the option `-pc_fieldsplit_schur_precondition` are inconsistent; precondition should be used everywhere.
2703feefa0e1SJacob Faibussowitsch 
2704a077d33dSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`,
2705a077d33dSBarry Smith           `MatSchurComplementSetAinvType()`, `PCLSC`, `PCFieldSplitSetSchurFactType()`
2706e69d4d44SBarry Smith @*/
2707d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurPre(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2708d71ae5a4SJacob Faibussowitsch {
2709e69d4d44SBarry Smith   PetscFunctionBegin;
27100700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2711cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurPre_C", (PC, PCFieldSplitSchurPreType, Mat), (pc, ptype, pre));
27123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2713e69d4d44SBarry Smith }
2714686bed4dSStefano Zampini 
2715d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurPrecondition(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2716d71ae5a4SJacob Faibussowitsch {
27179371c9d4SSatish Balay   return PCFieldSplitSetSchurPre(pc, ptype, pre);
27189371c9d4SSatish Balay } /* Deprecated name */
2719e69d4d44SBarry Smith 
272037a82bf0SJed Brown /*@
272137a82bf0SJed Brown   PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be
2722f1580f4eSBarry Smith   preconditioned.  See `PCFieldSplitSetSchurPre()` for details.
272337a82bf0SJed Brown 
2724c3339decSBarry Smith   Logically Collective
272537a82bf0SJed Brown 
2726f899ff85SJose E. Roman   Input Parameter:
272737a82bf0SJed Brown . pc - the preconditioner context
272837a82bf0SJed Brown 
272937a82bf0SJed Brown   Output Parameters:
2730d59693daSPierre 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`
2731d59693daSPierre Jolivet - pre   - matrix to use for preconditioning (with `PC_FIELDSPLIT_SCHUR_PRE_USER`), or `NULL`
273237a82bf0SJed Brown 
273337a82bf0SJed Brown   Level: intermediate
273437a82bf0SJed Brown 
2735d59693daSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCLSC`
273637a82bf0SJed Brown @*/
2737d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurPre(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre)
2738d71ae5a4SJacob Faibussowitsch {
273937a82bf0SJed Brown   PetscFunctionBegin;
274037a82bf0SJed Brown   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2741cac4c232SBarry Smith   PetscUseMethod(pc, "PCFieldSplitGetSchurPre_C", (PC, PCFieldSplitSchurPreType *, Mat *), (pc, ptype, pre));
27423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2743e69d4d44SBarry Smith }
2744e69d4d44SBarry Smith 
274545e7fc46SDmitry Karpeev /*@
2746f1580f4eSBarry Smith   PCFieldSplitSchurGetS -  extract the `MATSCHURCOMPLEMENT` object used by this `PCFIELDSPLIT` in case it needs to be configured separately
274745e7fc46SDmitry Karpeev 
274820f4b53cSBarry Smith   Not Collective
274945e7fc46SDmitry Karpeev 
275045e7fc46SDmitry Karpeev   Input Parameter:
275145e7fc46SDmitry Karpeev . pc - the preconditioner context
275245e7fc46SDmitry Karpeev 
275345e7fc46SDmitry Karpeev   Output Parameter:
2754470b340bSDmitry Karpeev . S - the Schur complement matrix
275545e7fc46SDmitry Karpeev 
275660f59c3bSBarry Smith   Level: advanced
275760f59c3bSBarry Smith 
2758f1580f4eSBarry Smith   Note:
2759f1580f4eSBarry Smith   This matrix should not be destroyed using `MatDestroy()`; rather, use `PCFieldSplitSchurRestoreS()`.
276045e7fc46SDmitry Karpeev 
276160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MATSCHURCOMPLEMENT`, `PCFieldSplitSchurRestoreS()`,
2762f1580f4eSBarry Smith           `MatCreateSchurComplement()`, `MatSchurComplementGetKSP()`, `MatSchurComplementComputeExplicitOperator()`, `MatGetSchurComplement()`
276345e7fc46SDmitry Karpeev @*/
2764d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurGetS(PC pc, Mat *S)
2765d71ae5a4SJacob Faibussowitsch {
276645e7fc46SDmitry Karpeev   const char    *t;
276745e7fc46SDmitry Karpeev   PetscBool      isfs;
276845e7fc46SDmitry Karpeev   PC_FieldSplit *jac;
276945e7fc46SDmitry Karpeev 
277045e7fc46SDmitry Karpeev   PetscFunctionBegin;
277145e7fc46SDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
27729566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetType((PetscObject)pc, &t));
27739566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
277428b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
277545e7fc46SDmitry Karpeev   jac = (PC_FieldSplit *)pc->data;
277663a3b9bcSJacob Faibussowitsch   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
2777470b340bSDmitry Karpeev   if (S) *S = jac->schur;
27783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
277945e7fc46SDmitry Karpeev }
278045e7fc46SDmitry Karpeev 
2781470b340bSDmitry Karpeev /*@
2782f1580f4eSBarry Smith   PCFieldSplitSchurRestoreS -  returns the `MATSCHURCOMPLEMENT` matrix used by this `PC`
2783470b340bSDmitry Karpeev 
278420f4b53cSBarry Smith   Not Collective
2785470b340bSDmitry Karpeev 
2786470b340bSDmitry Karpeev   Input Parameters:
2787470b340bSDmitry Karpeev + pc - the preconditioner context
2788a2b725a8SWilliam Gropp - S  - the Schur complement matrix
2789470b340bSDmitry Karpeev 
2790470b340bSDmitry Karpeev   Level: advanced
2791470b340bSDmitry Karpeev 
279260f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurGetS()`
2793470b340bSDmitry Karpeev @*/
2794d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSchurRestoreS(PC pc, Mat *S)
2795d71ae5a4SJacob Faibussowitsch {
2796470b340bSDmitry Karpeev   const char    *t;
2797470b340bSDmitry Karpeev   PetscBool      isfs;
2798470b340bSDmitry Karpeev   PC_FieldSplit *jac;
2799470b340bSDmitry Karpeev 
2800470b340bSDmitry Karpeev   PetscFunctionBegin;
2801470b340bSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
28029566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetType((PetscObject)pc, &t));
28039566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
280428b400f6SJacob Faibussowitsch   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
2805470b340bSDmitry Karpeev   jac = (PC_FieldSplit *)pc->data;
280663a3b9bcSJacob Faibussowitsch   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
28077827d75bSBarry Smith   PetscCheck(S && (*S == jac->schur), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatSchurComplement restored is not the same as gotten");
28083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2809470b340bSDmitry Karpeev }
2810470b340bSDmitry Karpeev 
2811d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType ptype, Mat pre)
2812d71ae5a4SJacob Faibussowitsch {
2813e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2814e69d4d44SBarry Smith 
2815e69d4d44SBarry Smith   PetscFunctionBegin;
2816084e4875SJed Brown   jac->schurpre = ptype;
2817a7476a74SDmitry Karpeev   if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) {
28189566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&jac->schur_user));
2819084e4875SJed Brown     jac->schur_user = pre;
28209566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)jac->schur_user));
2821084e4875SJed Brown   }
28223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2823e69d4d44SBarry Smith }
2824e69d4d44SBarry Smith 
2825d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre)
2826d71ae5a4SJacob Faibussowitsch {
282737a82bf0SJed Brown   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
282837a82bf0SJed Brown 
282937a82bf0SJed Brown   PetscFunctionBegin;
28306056e507SPierre Jolivet   if (ptype) *ptype = jac->schurpre;
28316056e507SPierre Jolivet   if (pre) *pre = jac->schur_user;
28323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
283337a82bf0SJed Brown }
283437a82bf0SJed Brown 
2835ab1df9f5SJed Brown /*@
28361d27aa22SBarry Smith   PCFieldSplitSetSchurFactType -  sets which blocks of the approximate block factorization to retain in the preconditioner {cite}`murphy2000note` and {cite}`ipsen2001note`
2837ab1df9f5SJed Brown 
2838c3339decSBarry Smith   Collective
2839ab1df9f5SJed Brown 
2840ab1df9f5SJed Brown   Input Parameters:
2841ab1df9f5SJed Brown + pc    - the preconditioner context
2842f1580f4eSBarry Smith - ftype - which blocks of factorization to retain, `PC_FIELDSPLIT_SCHUR_FACT_FULL` is default
2843ab1df9f5SJed Brown 
2844f1580f4eSBarry Smith   Options Database Key:
2845d59693daSPierre Jolivet . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - default is `full`
2846ab1df9f5SJed Brown 
2847ab1df9f5SJed Brown   Level: intermediate
2848ab1df9f5SJed Brown 
2849ab1df9f5SJed Brown   Notes:
2850366f9a6aSPierre Jolivet   The `full` factorization is
2851ab1df9f5SJed Brown 
2852a077d33dSBarry Smith   ```{math}
2853a077d33dSBarry Smith   \left(\begin{array}{cc} A & B \\
2854a077d33dSBarry Smith   C & E \\
2855a077d33dSBarry Smith   \end{array}\right) =
2856366f9a6aSPierre Jolivet   \left(\begin{array}{cc} I & 0 \\
2857366f9a6aSPierre Jolivet   C A^{-1} & I \\
2858a077d33dSBarry Smith   \end{array}\right)
2859a077d33dSBarry Smith   \left(\begin{array}{cc} A & 0 \\
2860a077d33dSBarry Smith   0 & S \\
2861a077d33dSBarry Smith   \end{array}\right)
2862a077d33dSBarry Smith   \left(\begin{array}{cc} I & A^{-1}B \\
2863a077d33dSBarry Smith   0 & I \\
2864366f9a6aSPierre Jolivet   \end{array}\right) = L D U,
2865a077d33dSBarry Smith   ```
2866a077d33dSBarry Smith 
2867366f9a6aSPierre 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$,
2868366f9a6aSPierre Jolivet   and `diag` is the diagonal part with the sign of $S$ flipped (because this makes the preconditioner positive definite for many formulations,
2869a077d33dSBarry Smith   thus allowing the use of `KSPMINRES)`. Sign flipping of $S$ can be turned off with `PCFieldSplitSetSchurScale()`.
2870a077d33dSBarry Smith 
2871a077d33dSBarry Smith   If $A$ and $S$ are solved exactly
2872366f9a6aSPierre Jolivet +  1 - `full` factorization is a direct solver.
2873366f9a6aSPierre 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.
2874366f9a6aSPierre 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.
2875ab1df9f5SJed Brown 
2876f1580f4eSBarry Smith   If the iteration count is very low, consider using `KSPFGMRES` or `KSPGCR` which can use one less preconditioner
28770ffb0e17SBarry 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.
28780ffb0e17SBarry Smith 
2879366f9a6aSPierre Jolivet   For symmetric problems in which $A$ is positive definite and $S$ is negative definite, `diag` can be used with `KSPMINRES`.
28800ffb0e17SBarry Smith 
2881366f9a6aSPierre 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$).
2882ab1df9f5SJed Brown 
28831d27aa22SBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurScale()`,
2884a077d33dSBarry Smith           [](sec_flexibleksp), `PCFieldSplitSetSchurPre()`
2885ab1df9f5SJed Brown @*/
2886d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurFactType(PC pc, PCFieldSplitSchurFactType ftype)
2887d71ae5a4SJacob Faibussowitsch {
2888ab1df9f5SJed Brown   PetscFunctionBegin;
2889ab1df9f5SJed Brown   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2890cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurFactType_C", (PC, PCFieldSplitSchurFactType), (pc, ftype));
28913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2892ab1df9f5SJed Brown }
2893ab1df9f5SJed Brown 
2894d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc, PCFieldSplitSchurFactType ftype)
2895d71ae5a4SJacob Faibussowitsch {
2896ab1df9f5SJed Brown   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2897ab1df9f5SJed Brown 
2898ab1df9f5SJed Brown   PetscFunctionBegin;
2899ab1df9f5SJed Brown   jac->schurfactorization = ftype;
29003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2901ab1df9f5SJed Brown }
2902ab1df9f5SJed Brown 
2903c096484dSStefano Zampini /*@
2904f1580f4eSBarry Smith   PCFieldSplitSetSchurScale -  Controls the sign flip of S for `PC_FIELDSPLIT_SCHUR_FACT_DIAG`.
2905c096484dSStefano Zampini 
2906c3339decSBarry Smith   Collective
2907c096484dSStefano Zampini 
2908c096484dSStefano Zampini   Input Parameters:
2909c096484dSStefano Zampini + pc    - the preconditioner context
2910c096484dSStefano Zampini - scale - scaling factor for the Schur complement
2911c096484dSStefano Zampini 
2912f1580f4eSBarry Smith   Options Database Key:
29131d27aa22SBarry Smith . -pc_fieldsplit_schur_scale <scale> - default is -1.0
2914c096484dSStefano Zampini 
2915c096484dSStefano Zampini   Level: intermediate
2916c096484dSStefano Zampini 
291742747ad1SJacob Faibussowitsch .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurFactType`, `PCFieldSplitSetSchurFactType()`
2918c096484dSStefano Zampini @*/
2919d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetSchurScale(PC pc, PetscScalar scale)
2920d71ae5a4SJacob Faibussowitsch {
2921c096484dSStefano Zampini   PetscFunctionBegin;
2922c096484dSStefano Zampini   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2923c096484dSStefano Zampini   PetscValidLogicalCollectiveScalar(pc, scale, 2);
2924cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetSchurScale_C", (PC, PetscScalar), (pc, scale));
29253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2926c096484dSStefano Zampini }
2927c096484dSStefano Zampini 
2928d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc, PetscScalar scale)
2929d71ae5a4SJacob Faibussowitsch {
2930c096484dSStefano Zampini   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2931c096484dSStefano Zampini 
2932c096484dSStefano Zampini   PetscFunctionBegin;
2933c096484dSStefano Zampini   jac->schurscale = scale;
29343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2935c096484dSStefano Zampini }
2936c096484dSStefano Zampini 
293730ad9308SMatthew Knepley /*@C
29388c03b21aSDmitry Karpeev   PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
293930ad9308SMatthew Knepley 
2940c3339decSBarry Smith   Collective
294130ad9308SMatthew Knepley 
294230ad9308SMatthew Knepley   Input Parameter:
294330ad9308SMatthew Knepley . pc - the preconditioner context
294430ad9308SMatthew Knepley 
294530ad9308SMatthew Knepley   Output Parameters:
2946a04f6461SBarry Smith + A00 - the (0,0) block
2947a04f6461SBarry Smith . A01 - the (0,1) block
2948a04f6461SBarry Smith . A10 - the (1,0) block
2949a04f6461SBarry Smith - A11 - the (1,1) block
295030ad9308SMatthew Knepley 
295130ad9308SMatthew Knepley   Level: advanced
295230ad9308SMatthew Knepley 
29535d83a8b1SBarry Smith   Note:
29545d83a8b1SBarry Smith   Use `NULL` for any unneeded output arguments
29555d83a8b1SBarry Smith 
295660f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `MatSchurComplementGetSubMatrices()`, `MatSchurComplementSetSubMatrices()`
295730ad9308SMatthew Knepley @*/
2958d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc, Mat *A00, Mat *A01, Mat *A10, Mat *A11)
2959d71ae5a4SJacob Faibussowitsch {
296030ad9308SMatthew Knepley   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
296130ad9308SMatthew Knepley 
296230ad9308SMatthew Knepley   PetscFunctionBegin;
29630700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
296408401ef6SPierre Jolivet   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
2965a04f6461SBarry Smith   if (A00) *A00 = jac->pmat[0];
2966a04f6461SBarry Smith   if (A01) *A01 = jac->B;
2967a04f6461SBarry Smith   if (A10) *A10 = jac->C;
2968a04f6461SBarry Smith   if (A11) *A11 = jac->pmat[1];
29693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
297030ad9308SMatthew Knepley }
297130ad9308SMatthew Knepley 
2972b09e027eSCarola Kruse /*@
29731d27aa22SBarry Smith   PCFieldSplitSetGKBTol -  Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
2974b09e027eSCarola Kruse 
2975c3339decSBarry Smith   Collective
2976e071a0a4SCarola Kruse 
2977b09e027eSCarola Kruse   Input Parameters:
2978b09e027eSCarola Kruse + pc        - the preconditioner context
2979b09e027eSCarola Kruse - tolerance - the solver tolerance
2980b09e027eSCarola Kruse 
2981f1580f4eSBarry Smith   Options Database Key:
29821d27aa22SBarry Smith . -pc_fieldsplit_gkb_tol <tolerance> - default is 1e-5
2983b09e027eSCarola Kruse 
2984b09e027eSCarola Kruse   Level: intermediate
2985b09e027eSCarola Kruse 
2986f1580f4eSBarry Smith   Note:
29871d27aa22SBarry Smith   The generalized GKB algorithm {cite}`arioli2013` uses a lower bound estimate of the error in energy norm as stopping criterion.
2988f1580f4eSBarry Smith   It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than
29891d27aa22SBarry Smith   this estimate, the stopping criterion is satisfactory in practical cases.
2990f1580f4eSBarry Smith 
299160f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBMaxit()`
2992b09e027eSCarola Kruse @*/
2993d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBTol(PC pc, PetscReal tolerance)
2994d71ae5a4SJacob Faibussowitsch {
2995b09e027eSCarola Kruse   PetscFunctionBegin;
2996b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2997de482cd7SCarola Kruse   PetscValidLogicalCollectiveReal(pc, tolerance, 2);
2998cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBTol_C", (PC, PetscReal), (pc, tolerance));
29993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3000b09e027eSCarola Kruse }
3001b09e027eSCarola Kruse 
3002d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc, PetscReal tolerance)
3003d71ae5a4SJacob Faibussowitsch {
3004b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3005b09e027eSCarola Kruse 
3006b09e027eSCarola Kruse   PetscFunctionBegin;
3007b09e027eSCarola Kruse   jac->gkbtol = tolerance;
30083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3009b09e027eSCarola Kruse }
3010b09e027eSCarola Kruse 
3011b09e027eSCarola Kruse /*@
301280670ca5SBarry Smith   PCFieldSplitSetGKBMaxit -  Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3013b09e027eSCarola Kruse 
3014c3339decSBarry Smith   Collective
3015b09e027eSCarola Kruse 
3016b09e027eSCarola Kruse   Input Parameters:
3017b09e027eSCarola Kruse + pc    - the preconditioner context
3018b09e027eSCarola Kruse - maxit - the maximum number of iterations
3019b09e027eSCarola Kruse 
3020f1580f4eSBarry Smith   Options Database Key:
30211d27aa22SBarry Smith . -pc_fieldsplit_gkb_maxit <maxit> - default is 100
3022b09e027eSCarola Kruse 
3023b09e027eSCarola Kruse   Level: intermediate
3024b09e027eSCarola Kruse 
302560f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBNu()`
3026b09e027eSCarola Kruse @*/
3027d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc, PetscInt maxit)
3028d71ae5a4SJacob Faibussowitsch {
3029b09e027eSCarola Kruse   PetscFunctionBegin;
3030b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3031de482cd7SCarola Kruse   PetscValidLogicalCollectiveInt(pc, maxit, 2);
3032cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBMaxit_C", (PC, PetscInt), (pc, maxit));
30333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3034b09e027eSCarola Kruse }
3035b09e027eSCarola Kruse 
3036d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc, PetscInt maxit)
3037d71ae5a4SJacob Faibussowitsch {
3038b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3039b09e027eSCarola Kruse 
3040b09e027eSCarola Kruse   PetscFunctionBegin;
3041b09e027eSCarola Kruse   jac->gkbmaxit = maxit;
30423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3043b09e027eSCarola Kruse }
3044b09e027eSCarola Kruse 
3045b09e027eSCarola Kruse /*@
30461d27aa22SBarry Smith   PCFieldSplitSetGKBDelay -  Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization {cite}`arioli2013` in `PCFIELDSPLIT`
3047e071a0a4SCarola Kruse   preconditioner.
3048b09e027eSCarola Kruse 
3049c3339decSBarry Smith   Collective
3050b09e027eSCarola Kruse 
3051b09e027eSCarola Kruse   Input Parameters:
3052b09e027eSCarola Kruse + pc    - the preconditioner context
3053b09e027eSCarola Kruse - delay - the delay window in the lower bound estimate
3054b09e027eSCarola Kruse 
3055f1580f4eSBarry Smith   Options Database Key:
30561d27aa22SBarry Smith . -pc_fieldsplit_gkb_delay <delay> - default is 5
3057b09e027eSCarola Kruse 
3058b09e027eSCarola Kruse   Level: intermediate
3059b09e027eSCarola Kruse 
30601d27aa22SBarry Smith   Notes:
30611d27aa22SBarry 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 $
30621d27aa22SBarry 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
30631d27aa22SBarry Smith   at least (`delay` + 1) iterations to stop.
3064f1580f4eSBarry Smith 
30651d27aa22SBarry Smith   For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to {cite}`arioli2013`
3066f1580f4eSBarry Smith 
306760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
3068b09e027eSCarola Kruse @*/
3069d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBDelay(PC pc, PetscInt delay)
3070d71ae5a4SJacob Faibussowitsch {
3071b09e027eSCarola Kruse   PetscFunctionBegin;
3072b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3073b09e027eSCarola Kruse   PetscValidLogicalCollectiveInt(pc, delay, 2);
3074cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBDelay_C", (PC, PetscInt), (pc, delay));
30753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3076b09e027eSCarola Kruse }
3077b09e027eSCarola Kruse 
3078d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc, PetscInt delay)
3079d71ae5a4SJacob Faibussowitsch {
3080b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3081b09e027eSCarola Kruse 
3082b09e027eSCarola Kruse   PetscFunctionBegin;
3083b09e027eSCarola Kruse   jac->gkbdelay = delay;
30843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3085b09e027eSCarola Kruse }
3086b09e027eSCarola Kruse 
3087b09e027eSCarola Kruse /*@
30881d27aa22SBarry Smith   PCFieldSplitSetGKBNu -  Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the
30891d27aa22SBarry Smith   Golub-Kahan bidiagonalization preconditioner {cite}`arioli2013` in `PCFIELDSPLIT`
3090b09e027eSCarola Kruse 
3091c3339decSBarry Smith   Collective
3092f1580f4eSBarry Smith 
3093f1580f4eSBarry Smith   Input Parameters:
3094f1580f4eSBarry Smith + pc - the preconditioner context
3095f1580f4eSBarry Smith - nu - the shift parameter
3096f1580f4eSBarry Smith 
309720f4b53cSBarry Smith   Options Database Key:
30981d27aa22SBarry Smith . -pc_fieldsplit_gkb_nu <nu> - default is 1
3099f1580f4eSBarry Smith 
3100f1580f4eSBarry Smith   Level: intermediate
3101b09e027eSCarola Kruse 
3102b09e027eSCarola Kruse   Notes:
31031d27aa22SBarry 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,
31041d27aa22SBarry 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
3105b09e027eSCarola Kruse   necessary to find a good balance in between the convergence of the inner and outer loop.
3106b09e027eSCarola Kruse 
31071d27aa22SBarry 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.
3108b09e027eSCarola Kruse 
310960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
3110b09e027eSCarola Kruse @*/
3111d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetGKBNu(PC pc, PetscReal nu)
3112d71ae5a4SJacob Faibussowitsch {
3113b09e027eSCarola Kruse   PetscFunctionBegin;
3114b09e027eSCarola Kruse   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3115de482cd7SCarola Kruse   PetscValidLogicalCollectiveReal(pc, nu, 2);
3116cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetGKBNu_C", (PC, PetscReal), (pc, nu));
31173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3118b09e027eSCarola Kruse }
3119b09e027eSCarola Kruse 
3120d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc, PetscReal nu)
3121d71ae5a4SJacob Faibussowitsch {
3122b09e027eSCarola Kruse   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3123b09e027eSCarola Kruse 
3124b09e027eSCarola Kruse   PetscFunctionBegin;
3125b09e027eSCarola Kruse   jac->gkbnu = nu;
31263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3127b09e027eSCarola Kruse }
3128b09e027eSCarola Kruse 
3129d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc, PCCompositeType type)
3130d71ae5a4SJacob Faibussowitsch {
313179416396SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
313279416396SBarry Smith 
313379416396SBarry Smith   PetscFunctionBegin;
313479416396SBarry Smith   jac->type = type;
31352e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
31362e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
31372e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
31382e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
31392e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
31402e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
31412e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
31422e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
31432e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
3144e071a0a4SCarola Kruse 
31453b224e63SBarry Smith   if (type == PC_COMPOSITE_SCHUR) {
31463b224e63SBarry Smith     pc->ops->apply          = PCApply_FieldSplit_Schur;
31477b665727SPierre Jolivet     pc->ops->applytranspose = PCApplyTranspose_FieldSplit_Schur;
3148*d484b384SBoris Martin     pc->ops->matapply       = NULL;
31493b224e63SBarry Smith     pc->ops->view           = PCView_FieldSplit_Schur;
315073716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit_Schur;
31512fa5cd67SKarl Rupp 
31529566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit_Schur));
31539566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", PCFieldSplitSetSchurPre_FieldSplit));
31549566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", PCFieldSplitGetSchurPre_FieldSplit));
31559566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", PCFieldSplitSetSchurFactType_FieldSplit));
31569566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", PCFieldSplitSetSchurScale_FieldSplit));
3157a51937d4SCarola Kruse   } else if (type == PC_COMPOSITE_GKB) {
3158a51937d4SCarola Kruse     pc->ops->apply          = PCApply_FieldSplit_GKB;
31597ff38633SStefano Zampini     pc->ops->applytranspose = NULL;
3160*d484b384SBoris Martin     pc->ops->matapply       = NULL;
3161a51937d4SCarola Kruse     pc->ops->view           = PCView_FieldSplit_GKB;
316273716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit_GKB;
3163e69d4d44SBarry Smith 
31649566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
31659566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", PCFieldSplitSetGKBTol_FieldSplit));
31669566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", PCFieldSplitSetGKBMaxit_FieldSplit));
31679566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", PCFieldSplitSetGKBNu_FieldSplit));
31689566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", PCFieldSplitSetGKBDelay_FieldSplit));
31693b224e63SBarry Smith   } else {
31703b224e63SBarry Smith     pc->ops->apply          = PCApply_FieldSplit;
31717ff38633SStefano Zampini     pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
3172*d484b384SBoris Martin     pc->ops->matapply       = PCMatApply_FieldSplit;
31733b224e63SBarry Smith     pc->ops->view           = PCView_FieldSplit;
317473716367SStefano Zampini     pc->ops->setuponblocks  = PCSetUpOnBlocks_FieldSplit;
31752fa5cd67SKarl Rupp 
31769566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
31773b224e63SBarry Smith   }
31783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
317979416396SBarry Smith }
318079416396SBarry Smith 
3181d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc, PetscInt bs)
3182d71ae5a4SJacob Faibussowitsch {
318351f519a2SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
318451f519a2SBarry Smith 
318551f519a2SBarry Smith   PetscFunctionBegin;
318663a3b9bcSJacob Faibussowitsch   PetscCheck(bs >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs);
31872472a847SBarry 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);
318851f519a2SBarry Smith   jac->bs = bs;
31893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
319051f519a2SBarry Smith }
319151f519a2SBarry Smith 
3192d71ae5a4SJacob Faibussowitsch static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[])
3193d71ae5a4SJacob Faibussowitsch {
31945ddf11f8SNicolas Barnafi   PC_FieldSplit    *jac           = (PC_FieldSplit *)pc->data;
31955ddf11f8SNicolas Barnafi   PC_FieldSplitLink ilink_current = jac->head;
31965ddf11f8SNicolas Barnafi   IS                is_owned;
31975ddf11f8SNicolas Barnafi 
31985ddf11f8SNicolas Barnafi   PetscFunctionBegin;
31995ddf11f8SNicolas Barnafi   jac->coordinates_set = PETSC_TRUE; // Internal flag
3200f3fa974cSJacob Faibussowitsch   PetscCall(MatGetOwnershipIS(pc->mat, &is_owned, NULL));
32015ddf11f8SNicolas Barnafi 
32025ddf11f8SNicolas Barnafi   while (ilink_current) {
32035ddf11f8SNicolas Barnafi     // For each IS, embed it to get local coords indces
32045ddf11f8SNicolas Barnafi     IS              is_coords;
32055ddf11f8SNicolas Barnafi     PetscInt        ndofs_block;
32065ddf11f8SNicolas Barnafi     const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block
32075ddf11f8SNicolas Barnafi 
32085ddf11f8SNicolas Barnafi     // Setting drop to true for safety. It should make no difference.
32099566063dSJacob Faibussowitsch     PetscCall(ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords));
32109566063dSJacob Faibussowitsch     PetscCall(ISGetLocalSize(is_coords, &ndofs_block));
32119566063dSJacob Faibussowitsch     PetscCall(ISGetIndices(is_coords, &block_dofs_enumeration));
32125ddf11f8SNicolas Barnafi 
32135ddf11f8SNicolas Barnafi     // Allocate coordinates vector and set it directly
3214f4f49eeaSPierre Jolivet     PetscCall(PetscMalloc1(ndofs_block * dim, &ilink_current->coords));
32155ddf11f8SNicolas Barnafi     for (PetscInt dof = 0; dof < ndofs_block; ++dof) {
3216ad540459SPierre Jolivet       for (PetscInt d = 0; d < dim; ++d) (ilink_current->coords)[dim * dof + d] = coords[dim * block_dofs_enumeration[dof] + d];
32175ddf11f8SNicolas Barnafi     }
32185ddf11f8SNicolas Barnafi     ilink_current->dim   = dim;
32195ddf11f8SNicolas Barnafi     ilink_current->ndofs = ndofs_block;
32209566063dSJacob Faibussowitsch     PetscCall(ISRestoreIndices(is_coords, &block_dofs_enumeration));
32219566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is_coords));
32225ddf11f8SNicolas Barnafi     ilink_current = ilink_current->next;
32235ddf11f8SNicolas Barnafi   }
32249566063dSJacob Faibussowitsch   PetscCall(ISDestroy(&is_owned));
32253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
32265ddf11f8SNicolas Barnafi }
32275ddf11f8SNicolas Barnafi 
3228bc08b0f1SBarry Smith /*@
3229f1580f4eSBarry Smith   PCFieldSplitSetType - Sets the type, `PCCompositeType`, of a `PCFIELDSPLIT`
323079416396SBarry Smith 
3231c3339decSBarry Smith   Collective
323279416396SBarry Smith 
3233d8d19677SJose E. Roman   Input Parameters:
3234a2b725a8SWilliam Gropp + pc   - the preconditioner context
3235a077d33dSBarry Smith - type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`,
3236a077d33dSBarry Smith          `PC_COMPOSITE_GKB`
323779416396SBarry Smith 
323879416396SBarry Smith   Options Database Key:
32391d27aa22SBarry Smith . -pc_fieldsplit_type <one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
324079416396SBarry Smith 
3241feefa0e1SJacob Faibussowitsch   Level: intermediate
324279416396SBarry Smith 
324360f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCCompositeType`, `PCCompositeGetType()`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`,
3244a077d33dSBarry Smith           `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`, `PCFieldSplitSetSchurFactType()`
324579416396SBarry Smith @*/
3246d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetType(PC pc, PCCompositeType type)
3247d71ae5a4SJacob Faibussowitsch {
324879416396SBarry Smith   PetscFunctionBegin;
32490700a824SBarry Smith   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
3250cac4c232SBarry Smith   PetscTryMethod(pc, "PCFieldSplitSetType_C", (PC, PCCompositeType), (pc, type));
32513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
325279416396SBarry Smith }
325379416396SBarry Smith 
3254b02e2d75SMatthew G Knepley /*@
3255f1580f4eSBarry Smith   PCFieldSplitGetType - Gets the type, `PCCompositeType`, of a `PCFIELDSPLIT`
3256b02e2d75SMatthew G Knepley 
3257b02e2d75SMatthew G Knepley   Not collective
3258b02e2d75SMatthew G Knepley 
3259b02e2d75SMatthew G Knepley   Input Parameter:
3260b02e2d75SMatthew G Knepley . pc - the preconditioner context
3261b02e2d75SMatthew G Knepley 
3262b02e2d75SMatthew G Knepley   Output Parameter:
3263f1580f4eSBarry Smith . type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`
3264b02e2d75SMatthew G Knepley 
3265feefa0e1SJacob Faibussowitsch   Level: intermediate
3266b02e2d75SMatthew G Knepley 
326760f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCompositeSetType()`, `PCFIELDSPLIT`, `PCCompositeType`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`,
3268f1580f4eSBarry Smith           `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `PC_COMPOSITE_SPECIAL`, `PC_COMPOSITE_SCHUR`
3269b02e2d75SMatthew G Knepley @*/
3270d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type)
3271d71ae5a4SJacob Faibussowitsch {
3272b02e2d75SMatthew G Knepley   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
3273b02e2d75SMatthew G Knepley 
3274b02e2d75SMatthew G Knepley   PetscFunctionBegin;
3275b02e2d75SMatthew G Knepley   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
32764f572ea9SToby Isaac   PetscAssertPointer(type, 2);
3277b02e2d75SMatthew G Knepley   *type = jac->type;
32783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3279b02e2d75SMatthew G Knepley }
3280b02e2d75SMatthew G Knepley 
32814ab8060aSDmitry Karpeev /*@
3282f1580f4eSBarry Smith   PCFieldSplitSetDMSplits - Flags whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible.
32834ab8060aSDmitry Karpeev 
3284c3339decSBarry Smith   Logically Collective
32854ab8060aSDmitry Karpeev 
32864ab8060aSDmitry Karpeev   Input Parameters:
32874ab8060aSDmitry Karpeev + pc  - the preconditioner context
3288f1580f4eSBarry Smith - flg - boolean indicating whether to use field splits defined by the `DM`
32894ab8060aSDmitry Karpeev 
32904ab8060aSDmitry Karpeev   Options Database Key:
3291f1580f4eSBarry Smith . -pc_fieldsplit_dm_splits <bool> - use the field splits defined by the `DM`
32924ab8060aSDmitry Karpeev 
3293feefa0e1SJacob Faibussowitsch   Level: intermediate
32944ab8060aSDmitry Karpeev 
329573ff1848SBarry Smith   Developer Note:
329673ff1848SBarry Smith   The name should be `PCFieldSplitSetUseDMSplits()`, similar change to options database
329773ff1848SBarry Smith 
3298f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
32994ab8060aSDmitry Karpeev @*/
3300d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDMSplits(PC pc, PetscBool flg)
3301d71ae5a4SJacob Faibussowitsch {
33024ab8060aSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
33034ab8060aSDmitry Karpeev   PetscBool      isfs;
33044ab8060aSDmitry Karpeev 
33054ab8060aSDmitry Karpeev   PetscFunctionBegin;
33064ab8060aSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
33074ab8060aSDmitry Karpeev   PetscValidLogicalCollectiveBool(pc, flg, 2);
33089566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
3309ad540459SPierre Jolivet   if (isfs) jac->dm_splits = flg;
33103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33114ab8060aSDmitry Karpeev }
33124ab8060aSDmitry Karpeev 
33134ab8060aSDmitry Karpeev /*@
3314f1580f4eSBarry Smith   PCFieldSplitGetDMSplits - Returns flag indicating whether `DMCreateFieldDecomposition()` should be used to define the splits in a `PCFIELDSPLIT`, whenever possible.
33154ab8060aSDmitry Karpeev 
33164ab8060aSDmitry Karpeev   Logically Collective
33174ab8060aSDmitry Karpeev 
33184ab8060aSDmitry Karpeev   Input Parameter:
33194ab8060aSDmitry Karpeev . pc - the preconditioner context
33204ab8060aSDmitry Karpeev 
33214ab8060aSDmitry Karpeev   Output Parameter:
3322f1580f4eSBarry Smith . flg - boolean indicating whether to use field splits defined by the `DM`
33234ab8060aSDmitry Karpeev 
3324feefa0e1SJacob Faibussowitsch   Level: intermediate
33254ab8060aSDmitry Karpeev 
332673ff1848SBarry Smith   Developer Note:
332773ff1848SBarry Smith   The name should be `PCFieldSplitGetUseDMSplits()`
332873ff1848SBarry Smith 
3329f8d70eaaSPierre Jolivet .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDMSplits()`, `DMCreateFieldDecomposition()`, `PCFieldSplitSetFields()`, `PCFieldSplitSetIS()`
33304ab8060aSDmitry Karpeev @*/
3331d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDMSplits(PC pc, PetscBool *flg)
3332d71ae5a4SJacob Faibussowitsch {
33334ab8060aSDmitry Karpeev   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
33344ab8060aSDmitry Karpeev   PetscBool      isfs;
33354ab8060aSDmitry Karpeev 
33364ab8060aSDmitry Karpeev   PetscFunctionBegin;
33374ab8060aSDmitry Karpeev   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
33384f572ea9SToby Isaac   PetscAssertPointer(flg, 2);
33399566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
33404ab8060aSDmitry Karpeev   if (isfs) {
33414ab8060aSDmitry Karpeev     if (flg) *flg = jac->dm_splits;
33424ab8060aSDmitry Karpeev   }
33433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33444ab8060aSDmitry Karpeev }
33454ab8060aSDmitry Karpeev 
33467b752e3dSPatrick Sanan /*@
3347f1580f4eSBarry Smith   PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries.
33487b752e3dSPatrick Sanan 
33497b752e3dSPatrick Sanan   Logically Collective
33507b752e3dSPatrick Sanan 
33517b752e3dSPatrick Sanan   Input Parameter:
33527b752e3dSPatrick Sanan . pc - the preconditioner context
33537b752e3dSPatrick Sanan 
33547b752e3dSPatrick Sanan   Output Parameter:
33557b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not
33567b752e3dSPatrick Sanan 
3357feefa0e1SJacob Faibussowitsch   Level: intermediate
33587b752e3dSPatrick Sanan 
335960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()`
33607b752e3dSPatrick Sanan @*/
3361d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc, PetscBool *flg)
3362d71ae5a4SJacob Faibussowitsch {
33637b752e3dSPatrick Sanan   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
33647b752e3dSPatrick Sanan 
33657b752e3dSPatrick Sanan   PetscFunctionBegin;
33667b752e3dSPatrick Sanan   *flg = jac->detect;
33673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33687b752e3dSPatrick Sanan }
33697b752e3dSPatrick Sanan 
33707b752e3dSPatrick Sanan /*@
3371f1580f4eSBarry Smith   PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether `PCFIELDSPLIT` will attempt to automatically determine fields based on zero diagonal entries.
33727b752e3dSPatrick Sanan 
33737b752e3dSPatrick Sanan   Logically Collective
33747b752e3dSPatrick Sanan 
33757b752e3dSPatrick Sanan   Input Parameter:
33767b752e3dSPatrick Sanan . pc - the preconditioner context
33777b752e3dSPatrick Sanan 
33787b752e3dSPatrick Sanan   Output Parameter:
33797b752e3dSPatrick Sanan . flg - boolean indicating whether to detect fields or not
33807b752e3dSPatrick Sanan 
33817b752e3dSPatrick Sanan   Options Database Key:
3382147403d9SBarry Smith . -pc_fieldsplit_detect_saddle_point <bool> - detect and use the saddle point
3383147403d9SBarry Smith 
3384feefa0e1SJacob Faibussowitsch   Level: intermediate
338560f59c3bSBarry Smith 
3386f1580f4eSBarry Smith   Note:
3387f1580f4eSBarry 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()`).
33887b752e3dSPatrick Sanan 
338960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCFIELDSPLIT`, `PCFieldSplitGetDetectSaddlePoint()`, `PCFieldSplitSetType()`, `PCFieldSplitSetSchurPre()`, `PC_FIELDSPLIT_SCHUR_PRE_SELF`
33907b752e3dSPatrick Sanan @*/
3391d71ae5a4SJacob Faibussowitsch PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc, PetscBool flg)
3392d71ae5a4SJacob Faibussowitsch {
33937b752e3dSPatrick Sanan   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
33947b752e3dSPatrick Sanan 
33957b752e3dSPatrick Sanan   PetscFunctionBegin;
33967b752e3dSPatrick Sanan   jac->detect = flg;
33977b752e3dSPatrick Sanan   if (jac->detect) {
33989566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR));
33999566063dSJacob Faibussowitsch     PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL));
34007b752e3dSPatrick Sanan   }
34013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34027b752e3dSPatrick Sanan }
34037b752e3dSPatrick Sanan 
34040971522cSBarry Smith /*MC
3405a8c7a070SBarry Smith   PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
34060b4b7b1cSBarry Smith   collections of variables (that may overlap) called fields or splits. Each field often represents a different continuum variable
34070b4b7b1cSBarry Smith   represented on a grid, such as velocity, pressure, or temperature.
34080b4b7b1cSBarry Smith   In the literature these are sometimes called block preconditioners; but should not be confused with `PCBJACOBI`.
34090b4b7b1cSBarry Smith   See [the users manual section on "Solving Block Matrices"](sec_block_matrices) for more details.
34100971522cSBarry Smith 
341179416396SBarry Smith   Options Database Keys:
3412de37d9f1SPatrick Sanan +   -pc_fieldsplit_%d_fields <a,b,..>                                                - indicates the fields to be used in the `%d`'th split
341381540f2fSBarry Smith .   -pc_fieldsplit_default                                                           - automatically add any fields to additional splits that have not
3414de37d9f1SPatrick Sanan                                                                                        been supplied explicitly by `-pc_fieldsplit_%d_fields`
341581540f2fSBarry Smith .   -pc_fieldsplit_block_size <bs>                                                   - size of block that defines fields (i.e. there are bs fields)
341680670ca5SBarry Smith                                                                                        when the matrix is not of `MatType` `MATNEST`
3417a51937d4SCarola Kruse .   -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting
3418d59693daSPierre Jolivet .   -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full>                     - default is `a11`; see `PCFieldSplitSetSchurPre()`
34191d27aa22SBarry Smith .   -pc_fieldsplit_schur_fact_type <diag,lower,upper,full>                           - set factorization type when using `-pc_fieldsplit_type schur`;
34201d27aa22SBarry Smith                                                                                        see `PCFieldSplitSetSchurFactType()`
342173ff1848SBarry Smith .   -pc_fieldsplit_dm_splits <true,false> (default is true)                          - Whether to use `DMCreateFieldDecomposition()` for splits
3422fb6809a2SPatrick Sanan -   -pc_fieldsplit_detect_saddle_point                                               - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver
342379416396SBarry Smith 
3424de37d9f1SPatrick Sanan   Options prefixes for inner solvers when using the Schur complement preconditioner are `-fieldsplit_0_` and `-fieldsplit_1_` .
3425de37d9f1SPatrick Sanan   The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is `-fieldsplit_0_`
342660f59c3bSBarry Smith   For all other solvers they are `-fieldsplit_%d_` for the `%d`'th field; use `-fieldsplit_` for all fields.
342760f59c3bSBarry Smith 
342822399129SNuno Nobre   To set options on the solvers for all blocks, prepend `-fieldsplit_` to all the `PC`
342922399129SNuno Nobre   options database keys. For example, `-fieldsplit_pc_type ilu` `-fieldsplit_pc_factor_levels 1`.
343060f59c3bSBarry Smith 
343160f59c3bSBarry Smith   To set the options on the solvers separate for each block call `PCFieldSplitGetSubKSP()`
343260f59c3bSBarry Smith   and set the options directly on the resulting `KSP` object
343360f59c3bSBarry Smith 
343460f59c3bSBarry Smith   Level: intermediate
34355d4c12cdSJungho Lee 
3436c8a0d604SMatthew G Knepley   Notes:
343780670ca5SBarry Smith   Use `PCFieldSplitSetFields()` to set splits defined by "strided" entries or with a `MATNEST` and `PCFieldSplitSetIS()`
3438f1580f4eSBarry Smith   to define a split by an arbitrary collection of entries.
3439d32f9abdSBarry Smith 
344073ff1848SBarry Smith   If no splits are set, the default is used. If a `DM` is associated with the `PC` and it supports
344180670ca5SBarry 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,
3442de37d9f1SPatrick Sanan   beginning at 0 then 1, etc to bs-1. The block size can be set with `PCFieldSplitSetBlockSize()`,
3443d32f9abdSBarry Smith   if this is not called the block size defaults to the blocksize of the second matrix passed
3444de37d9f1SPatrick Sanan   to `KSPSetOperators()`/`PCSetOperators()`.
3445d32f9abdSBarry Smith 
3446de37d9f1SPatrick Sanan   For the Schur complement preconditioner if
3447de37d9f1SPatrick Sanan   ```{math}
3448de37d9f1SPatrick Sanan     J = \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{10} & A_{11} \end{array}\right]
3449de37d9f1SPatrick Sanan   ```
3450e69d4d44SBarry Smith 
3451de37d9f1SPatrick Sanan   the preconditioner using `full` factorization is logically
3452de37d9f1SPatrick Sanan   ```{math}
3453f820a28cSNuno 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]
3454de37d9f1SPatrick Sanan       ```
3455cee94454SNuno Nobre   where the action of $\text{ksp}(A_{00})$ is applied using the `KSP` solver with prefix `-fieldsplit_0_`.  $S$ is the Schur complement
3456de37d9f1SPatrick Sanan   ```{math}
3457223e5b4fSPatrick Sanan      S = A_{11} - A_{10} \text{ksp}(A_{00}) A_{01}
3458de37d9f1SPatrick Sanan   ```
34597cbeddf0SNuno 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`
34607cbeddf0SNuno 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
34617cbeddf0SNuno Nobre   0th index, the `KSP` associated with `-fieldsplit_0_`, and at its 1st index, the `KSP` corresponding to `-fieldsplit_1_`.
3462d82b6cdfSNuno 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$.
3463de37d9f1SPatrick Sanan 
3464de37d9f1SPatrick Sanan   The factorization type is set using `-pc_fieldsplit_schur_fact_type <diag, lower, upper, full>`. `full` is shown above,
3465de37d9f1SPatrick Sanan   `diag` gives
3466de37d9f1SPatrick Sanan   ```{math}
3467f820a28cSNuno Nobre     \left[\begin{array}{cc} \text{ksp}(A_{00}) & 0 \\  0 & -\text{ksp}(S) \end{array}\right]
3468de37d9f1SPatrick Sanan   ```
3469de37d9f1SPatrick 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
3470de37d9f1SPatrick Sanan   can be turned off with `PCFieldSplitSetSchurScale()` or by command line `-pc_fieldsplit_schur_scale 1.0`. The `lower` factorization is the inverse of
3471de37d9f1SPatrick Sanan   ```{math}
3472de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & 0 \\  A_{10} & S \end{array}\right]
3473de37d9f1SPatrick Sanan   ```
3474cee94454SNuno Nobre   where the inverses of $A_{00}$ and $S$ are applied using `KSP`s. The upper factorization is the inverse of
3475de37d9f1SPatrick Sanan   ```{math}
3476de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & A_{01} \\  0 & S \end{array}\right]
3477de37d9f1SPatrick Sanan   ```
3478de37d9f1SPatrick Sanan   where again the inverses of $A_{00}$ and $S$ are applied using `KSP`s.
3479de37d9f1SPatrick Sanan 
3480de37d9f1SPatrick Sanan   If only one set of indices (one `IS`) is provided with `PCFieldSplitSetIS()` then the complement of that `IS`
348180670ca5SBarry Smith   is used automatically for a second submatrix.
3482edf189efSBarry Smith 
3483f1580f4eSBarry Smith   The fieldsplit preconditioner cannot currently be used with the `MATBAIJ` or `MATSBAIJ` data formats if the blocksize is larger than 1.
348480670ca5SBarry Smith   Generally it should be used with the `MATAIJ` or `MATNEST` `MatType`
3485ff218e97SBarry Smith 
348680670ca5SBarry Smith   The forms of these preconditioners are closely related, if not identical, to forms derived as "Distributive Iterations", see,
34871d569b8fSBarry Smith   for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling {cite}`wesseling2009`.
348880670ca5SBarry Smith   One can also use `PCFIELDSPLIT` inside a smoother resulting in "Distributive Smoothers".
34890716a85fSBarry Smith 
3490de37d9f1SPatrick Sanan   See "A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations" {cite}`elman2008tcp`.
3491a6a584a2SBarry Smith 
3492de37d9f1SPatrick Sanan   The Constrained Pressure Preconditioner (CPR) can be implemented using `PCCOMPOSITE` with `PCGALERKIN`. CPR first solves an $R A P$ subsystem, updates the
3493de37d9f1SPatrick Sanan   residual on all variables (`PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)`), and then applies a simple ILU like preconditioner on all the variables.
3494a51937d4SCarola Kruse 
3495de37d9f1SPatrick Sanan   The generalized Golub-Kahan bidiagonalization preconditioner (GKB) can be applied to symmetric $2 \times 2$ block matrices of the shape
3496de37d9f1SPatrick Sanan   ```{math}
3497de37d9f1SPatrick Sanan     \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{01}' & 0 \end{array}\right]
3498de37d9f1SPatrick Sanan   ```
34991d569b8fSBarry 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}'$.
3500de37d9f1SPatrick 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_`.
3501a51937d4SCarola Kruse 
35020b4b7b1cSBarry Smith   Some `PCFIELDSPLIT` variants are called physics-based preconditioners, since the preconditioner takes into account the underlying physics of the
35030b4b7b1cSBarry Smith   problem. But this nomenclature is not well-defined.
35040b4b7b1cSBarry Smith 
350560f59c3bSBarry Smith   Developer Note:
350660f59c3bSBarry Smith   The Schur complement functionality of `PCFIELDSPLIT` should likely be factored into its own `PC` thus simplifying the implementation of the preconditioners and their
350760f59c3bSBarry Smith   user API.
3508f1580f4eSBarry Smith 
350960f59c3bSBarry Smith .seealso: [](sec_block_matrices), `PC`, `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCLSC`,
3510db781477SPatrick Sanan           `PCFieldSplitGetSubKSP()`, `PCFieldSplitSchurGetSubKSP()`, `PCFieldSplitSetFields()`,
3511db781477SPatrick Sanan           `PCFieldSplitSetType()`, `PCFieldSplitSetIS()`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitSetSchurFactType()`,
3512db781477SPatrick Sanan           `MatSchurComplementSetAinvType()`, `PCFieldSplitSetSchurScale()`, `PCFieldSplitSetDetectSaddlePoint()`
35130971522cSBarry Smith M*/
35140971522cSBarry Smith 
3515d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc)
3516d71ae5a4SJacob Faibussowitsch {
35170971522cSBarry Smith   PC_FieldSplit *jac;
35180971522cSBarry Smith 
35190971522cSBarry Smith   PetscFunctionBegin;
35204dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&jac));
35212fa5cd67SKarl Rupp 
35220971522cSBarry Smith   jac->bs                 = -1;
35233e197d65SBarry Smith   jac->type               = PC_COMPOSITE_MULTIPLICATIVE;
3524e6cab6aaSJed Brown   jac->schurpre           = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
3525c9c6ffaaSJed Brown   jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL;
3526c096484dSStefano Zampini   jac->schurscale         = -1.0;
3527fbe7908bSJed Brown   jac->dm_splits          = PETSC_TRUE;
3528a51937d4SCarola Kruse   jac->gkbtol             = 1e-5;
3529a51937d4SCarola Kruse   jac->gkbdelay           = 5;
3530a51937d4SCarola Kruse   jac->gkbnu              = 1;
3531a51937d4SCarola Kruse   jac->gkbmaxit           = 100;
353251f519a2SBarry Smith 
35330971522cSBarry Smith   pc->data = (void *)jac;
35340971522cSBarry Smith 
35350971522cSBarry Smith   pc->ops->setup           = PCSetUp_FieldSplit;
3536574deadeSBarry Smith   pc->ops->reset           = PCReset_FieldSplit;
35370971522cSBarry Smith   pc->ops->destroy         = PCDestroy_FieldSplit;
35380971522cSBarry Smith   pc->ops->setfromoptions  = PCSetFromOptions_FieldSplit;
35390a545947SLisandro Dalcin   pc->ops->applyrichardson = NULL;
35400971522cSBarry Smith 
35419566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", PCFieldSplitSchurGetSubKSP_FieldSplit));
35429566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", PCFieldSplitSetFields_FieldSplit));
35439566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_FieldSplit));
35449566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", PCFieldSplitSetType_FieldSplit));
35459566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", PCFieldSplitSetBlockSize_FieldSplit));
35469566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", PCFieldSplitRestrictIS_FieldSplit));
35479566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_FieldSplit));
35487ff38633SStefano Zampini 
35497ff38633SStefano Zampini   /* Initialize function pointers */
35507ff38633SStefano Zampini   PetscCall(PCFieldSplitSetType(pc, jac->type));
35513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35520971522cSBarry Smith }
3553