xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
1 #include <petsc/private/pcimpl.h>  /*I "petscpc.h" I*/
2 #include <petsc/private/kspimpl.h> /*  This is needed to provide the appropriate PETSC_EXTERN for KSP_Solve_FS ....*/
3 #include <petscdm.h>
4 
5 const char *const PCFieldSplitSchurPreTypes[]  = {"SELF", "SELFP", "A11", "USER", "FULL", "PCFieldSplitSchurPreType", "PC_FIELDSPLIT_SCHUR_PRE_", NULL};
6 const char *const PCFieldSplitSchurFactTypes[] = {"DIAG", "LOWER", "UPPER", "FULL", "PCFieldSplitSchurFactType", "PC_FIELDSPLIT_SCHUR_FACT_", NULL};
7 
8 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;
9 
10 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
11 struct _PC_FieldSplitLink {
12   KSP               ksp;
13   Vec               x, y, z;
14   char             *splitname;
15   PetscInt          nfields;
16   PetscInt         *fields, *fields_col;
17   VecScatter        sctx;
18   IS                is, is_col;
19   PC_FieldSplitLink next, previous;
20   PetscLogEvent     event;
21 
22   /* Used only when setting coordinates with PCSetCoordinates */
23   PetscInt   dim;
24   PetscInt   ndofs;
25   PetscReal *coords;
26 };
27 
28 typedef struct {
29   PCCompositeType type;
30   PetscBool       defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
31   PetscBool       splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */
32   PetscInt        bs;           /* Block size for IS and Mat structures */
33   PetscInt        nsplits;      /* Number of field divisions defined */
34   Vec            *x, *y, w1, w2;
35   Mat            *mat;    /* The diagonal block for each split */
36   Mat            *pmat;   /* The preconditioning diagonal block for each split */
37   Mat            *Afield; /* The rows of the matrix associated with each split */
38   PetscBool       issetup;
39 
40   /* Only used when Schur complement preconditioning is used */
41   Mat                       B;          /* The (0,1) block */
42   Mat                       C;          /* The (1,0) block */
43   Mat                       schur;      /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */
44   Mat                       schurp;     /* Assembled approximation to S built by MatSchurComplement to be used as a preconditioning matrix when solving with S */
45   Mat                       schur_user; /* User-provided preconditioning matrix for the Schur complement */
46   PCFieldSplitSchurPreType  schurpre;   /* Determines which preconditioning matrix is used for the Schur complement */
47   PCFieldSplitSchurFactType schurfactorization;
48   KSP                       kspschur;   /* The solver for S */
49   KSP                       kspupper;   /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */
50   PetscScalar               schurscale; /* Scaling factor for the Schur complement solution with DIAG factorization */
51 
52   /* Only used when Golub-Kahan bidiagonalization preconditioning is used */
53   Mat          H;           /* The modified matrix H = A00 + nu*A01*A01'              */
54   PetscReal    gkbtol;      /* Stopping tolerance for lower bound estimate            */
55   PetscInt     gkbdelay;    /* The delay window for the stopping criterion            */
56   PetscReal    gkbnu;       /* Parameter for augmented Lagrangian H = A + nu*A01*A01' */
57   PetscInt     gkbmaxit;    /* Maximum number of iterations for outer loop            */
58   PetscBool    gkbmonitor;  /* Monitor for gkb iterations and the lower bound error   */
59   PetscViewer  gkbviewer;   /* Viewer context for gkbmonitor                          */
60   Vec          u, v, d, Hu; /* Work vectors for the GKB algorithm                     */
61   PetscScalar *vecz;        /* Contains intermediate values, eg for lower bound       */
62 
63   PC_FieldSplitLink head;
64   PetscBool         isrestrict;       /* indicates PCFieldSplitRestrictIS() has been last called on this object, hack */
65   PetscBool         suboptionsset;    /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */
66   PetscBool         dm_splits;        /* Whether to use DMCreateFieldDecomposition() whenever possible */
67   PetscBool         diag_use_amat;    /* Whether to extract diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */
68   PetscBool         offdiag_use_amat; /* Whether to extract off-diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */
69   PetscBool         detect;           /* Whether to form 2-way split by finding zero diagonal entries */
70   PetscBool         coordinates_set;  /* Whether PCSetCoordinates has been called */
71 } PC_FieldSplit;
72 
73 /*
74     Notes:
75     there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
76    inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
77    PC you could change this.
78 */
79 
80 /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it.  This way the
81 * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
82 static Mat FieldSplitSchurPre(PC_FieldSplit *jac) {
83   switch (jac->schurpre) {
84   case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur;
85   case PC_FIELDSPLIT_SCHUR_PRE_SELFP: return jac->schurp;
86   case PC_FIELDSPLIT_SCHUR_PRE_A11: return jac->pmat[1];
87   case PC_FIELDSPLIT_SCHUR_PRE_FULL: /* We calculate this and store it in schur_user */
88   case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
89   default: return jac->schur_user ? jac->schur_user : jac->pmat[1];
90   }
91 }
92 
93 #include <petscdraw.h>
94 static PetscErrorCode PCView_FieldSplit(PC pc, PetscViewer viewer) {
95   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
96   PetscBool         iascii, isdraw;
97   PetscInt          i, j;
98   PC_FieldSplitLink ilink = jac->head;
99 
100   PetscFunctionBegin;
101   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
102   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
103   if (iascii) {
104     if (jac->bs > 0) {
105       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with %s composition: total splits = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits, jac->bs));
106     } else {
107       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with %s composition: total splits = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits));
108     }
109     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for blocks\n"));
110     if (jac->diag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for diagonal blocks\n"));
111     if (jac->offdiag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for off-diagonal blocks\n"));
112     PetscCall(PetscViewerASCIIPrintf(viewer, "  Solver info for each split is in the following KSP objects:\n"));
113     for (i = 0; i < jac->nsplits; i++) {
114       if (ilink->fields) {
115         PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Fields ", i));
116         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
117         for (j = 0; j < ilink->nfields; j++) {
118           if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
119           PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
120         }
121         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
122         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
123       } else {
124         PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Defined by IS\n", i));
125       }
126       PetscCall(KSPView(ilink->ksp, viewer));
127       ilink = ilink->next;
128     }
129   }
130 
131   if (isdraw) {
132     PetscDraw draw;
133     PetscReal x, y, w, wd;
134 
135     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
136     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
137     w  = 2 * PetscMin(1.0 - x, x);
138     wd = w / (jac->nsplits + 1);
139     x  = x - wd * (jac->nsplits - 1) / 2.0;
140     for (i = 0; i < jac->nsplits; i++) {
141       PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
142       PetscCall(KSPView(ilink->ksp, viewer));
143       PetscCall(PetscDrawPopCurrentPoint(draw));
144       x += wd;
145       ilink = ilink->next;
146     }
147   }
148   PetscFunctionReturn(0);
149 }
150 
151 static PetscErrorCode PCView_FieldSplit_Schur(PC pc, PetscViewer viewer) {
152   PC_FieldSplit             *jac = (PC_FieldSplit *)pc->data;
153   PetscBool                  iascii, isdraw;
154   PetscInt                   i, j;
155   PC_FieldSplitLink          ilink = jac->head;
156   MatSchurComplementAinvType atype;
157 
158   PetscFunctionBegin;
159   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
160   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
161   if (iascii) {
162     if (jac->bs > 0) {
163       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with Schur preconditioner, blocksize = %" PetscInt_FMT ", factorization %s\n", jac->bs, PCFieldSplitSchurFactTypes[jac->schurfactorization]));
164     } else {
165       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with Schur preconditioner, factorization %s\n", PCFieldSplitSchurFactTypes[jac->schurfactorization]));
166     }
167     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for blocks\n"));
168     switch (jac->schurpre) {
169     case PC_FIELDSPLIT_SCHUR_PRE_SELF: PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from S itself\n")); break;
170     case PC_FIELDSPLIT_SCHUR_PRE_SELFP:
171       PetscCall(MatSchurComplementGetAinvType(jac->schur, &atype));
172       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 "))));
173       break;
174     case PC_FIELDSPLIT_SCHUR_PRE_A11: PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from A11\n")); break;
175     case PC_FIELDSPLIT_SCHUR_PRE_FULL: PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from the exact Schur complement\n")); break;
176     case PC_FIELDSPLIT_SCHUR_PRE_USER:
177       if (jac->schur_user) {
178         PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from user provided matrix\n"));
179       } else {
180         PetscCall(PetscViewerASCIIPrintf(viewer, "  Preconditioner for the Schur complement formed from A11\n"));
181       }
182       break;
183     default: SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre);
184     }
185     PetscCall(PetscViewerASCIIPrintf(viewer, "  Split info:\n"));
186     PetscCall(PetscViewerASCIIPushTab(viewer));
187     for (i = 0; i < jac->nsplits; i++) {
188       if (ilink->fields) {
189         PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Fields ", i));
190         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
191         for (j = 0; j < ilink->nfields; j++) {
192           if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
193           PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
194         }
195         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
196         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
197       } else {
198         PetscCall(PetscViewerASCIIPrintf(viewer, "Split number %" PetscInt_FMT " Defined by IS\n", i));
199       }
200       ilink = ilink->next;
201     }
202     PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for A00 block\n"));
203     PetscCall(PetscViewerASCIIPushTab(viewer));
204     if (jac->head) {
205       PetscCall(KSPView(jac->head->ksp, viewer));
206     } else PetscCall(PetscViewerASCIIPrintf(viewer, "  not yet available\n"));
207     PetscCall(PetscViewerASCIIPopTab(viewer));
208     if (jac->head && jac->kspupper != jac->head->ksp) {
209       PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for upper A00 in upper triangular factor \n"));
210       PetscCall(PetscViewerASCIIPushTab(viewer));
211       if (jac->kspupper) PetscCall(KSPView(jac->kspupper, viewer));
212       else PetscCall(PetscViewerASCIIPrintf(viewer, "  not yet available\n"));
213       PetscCall(PetscViewerASCIIPopTab(viewer));
214     }
215     PetscCall(PetscViewerASCIIPrintf(viewer, "KSP solver for S = A11 - A10 inv(A00) A01 \n"));
216     PetscCall(PetscViewerASCIIPushTab(viewer));
217     if (jac->kspschur) {
218       PetscCall(KSPView(jac->kspschur, viewer));
219     } else {
220       PetscCall(PetscViewerASCIIPrintf(viewer, "  not yet available\n"));
221     }
222     PetscCall(PetscViewerASCIIPopTab(viewer));
223     PetscCall(PetscViewerASCIIPopTab(viewer));
224   } else if (isdraw && jac->head) {
225     PetscDraw draw;
226     PetscReal x, y, w, wd, h;
227     PetscInt  cnt = 2;
228     char      str[32];
229 
230     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
231     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
232     if (jac->kspupper != jac->head->ksp) cnt++;
233     w  = 2 * PetscMin(1.0 - x, x);
234     wd = w / (cnt + 1);
235 
236     PetscCall(PetscSNPrintf(str, 32, "Schur fact. %s", PCFieldSplitSchurFactTypes[jac->schurfactorization]));
237     PetscCall(PetscDrawStringBoxed(draw, x, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
238     y -= h;
239     if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER && !jac->schur_user) {
240       PetscCall(PetscSNPrintf(str, 32, "Prec. for Schur from %s", PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11]));
241     } else {
242       PetscCall(PetscSNPrintf(str, 32, "Prec. for Schur from %s", PCFieldSplitSchurPreTypes[jac->schurpre]));
243     }
244     PetscCall(PetscDrawStringBoxed(draw, x + wd * (cnt - 1) / 2.0, y, PETSC_DRAW_RED, PETSC_DRAW_BLACK, str, NULL, &h));
245     y -= h;
246     x = x - wd * (cnt - 1) / 2.0;
247 
248     PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
249     PetscCall(KSPView(jac->head->ksp, viewer));
250     PetscCall(PetscDrawPopCurrentPoint(draw));
251     if (jac->kspupper != jac->head->ksp) {
252       x += wd;
253       PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
254       PetscCall(KSPView(jac->kspupper, viewer));
255       PetscCall(PetscDrawPopCurrentPoint(draw));
256     }
257     x += wd;
258     PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
259     PetscCall(KSPView(jac->kspschur, viewer));
260     PetscCall(PetscDrawPopCurrentPoint(draw));
261   }
262   PetscFunctionReturn(0);
263 }
264 
265 static PetscErrorCode PCView_FieldSplit_GKB(PC pc, PetscViewer viewer) {
266   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
267   PetscBool         iascii, isdraw;
268   PetscInt          i, j;
269   PC_FieldSplitLink ilink = jac->head;
270 
271   PetscFunctionBegin;
272   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
273   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
274   if (iascii) {
275     if (jac->bs > 0) {
276       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with %s composition: total splits = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits, jac->bs));
277     } else {
278       PetscCall(PetscViewerASCIIPrintf(viewer, "  FieldSplit with %s composition: total splits = %" PetscInt_FMT "\n", PCCompositeTypes[jac->type], jac->nsplits));
279     }
280     if (pc->useAmat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for blocks\n"));
281     if (jac->diag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for diagonal blocks\n"));
282     if (jac->offdiag_use_amat) PetscCall(PetscViewerASCIIPrintf(viewer, "  using Amat (not Pmat) as operator for off-diagonal blocks\n"));
283 
284     PetscCall(PetscViewerASCIIPrintf(viewer, "  Stopping tolerance=%.1e, delay in error estimate=%" PetscInt_FMT ", maximum iterations=%" PetscInt_FMT "\n", (double)jac->gkbtol, jac->gkbdelay, jac->gkbmaxit));
285     PetscCall(PetscViewerASCIIPrintf(viewer, "  Solver info for H = A00 + nu*A01*A01' matrix:\n"));
286     PetscCall(PetscViewerASCIIPushTab(viewer));
287 
288     if (ilink->fields) {
289       PetscCall(PetscViewerASCIIPrintf(viewer, "Split number 0 Fields "));
290       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
291       for (j = 0; j < ilink->nfields; j++) {
292         if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
293         PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, ilink->fields[j]));
294       }
295       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
296       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
297     } else {
298       PetscCall(PetscViewerASCIIPrintf(viewer, "Split number 0 Defined by IS\n"));
299     }
300     PetscCall(KSPView(ilink->ksp, viewer));
301 
302     PetscCall(PetscViewerASCIIPopTab(viewer));
303   }
304 
305   if (isdraw) {
306     PetscDraw draw;
307     PetscReal x, y, w, wd;
308 
309     PetscCall(PetscViewerDrawGetDraw(viewer, 0, &draw));
310     PetscCall(PetscDrawGetCurrentPoint(draw, &x, &y));
311     w  = 2 * PetscMin(1.0 - x, x);
312     wd = w / (jac->nsplits + 1);
313     x  = x - wd * (jac->nsplits - 1) / 2.0;
314     for (i = 0; i < jac->nsplits; i++) {
315       PetscCall(PetscDrawPushCurrentPoint(draw, x, y));
316       PetscCall(KSPView(ilink->ksp, viewer));
317       PetscCall(PetscDrawPopCurrentPoint(draw));
318       x += wd;
319       ilink = ilink->next;
320     }
321   }
322   PetscFunctionReturn(0);
323 }
324 
325 /* Precondition: jac->bs is set to a meaningful value */
326 static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc) {
327   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
328   PetscInt       i, nfields, *ifields, nfields_col, *ifields_col;
329   PetscBool      flg, flg_col;
330   char           optionname[128], splitname[8], optionname_col[128];
331 
332   PetscFunctionBegin;
333   PetscCall(PetscMalloc1(jac->bs, &ifields));
334   PetscCall(PetscMalloc1(jac->bs, &ifields_col));
335   for (i = 0, flg = PETSC_TRUE;; i++) {
336     PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
337     PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%" PetscInt_FMT "_fields", i));
338     PetscCall(PetscSNPrintf(optionname_col, sizeof(optionname_col), "-pc_fieldsplit_%" PetscInt_FMT "_fields_col", i));
339     nfields     = jac->bs;
340     nfields_col = jac->bs;
341     PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg));
342     PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname_col, ifields_col, &nfields_col, &flg_col));
343     if (!flg) break;
344     else if (flg && !flg_col) {
345       PetscCheck(nfields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields");
346       PetscCall(PCFieldSplitSetFields(pc, splitname, nfields, ifields, ifields));
347     } else {
348       PetscCheck(nfields && nfields_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields");
349       PetscCheck(nfields == nfields_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Number of row and column fields must match");
350       PetscCall(PCFieldSplitSetFields(pc, splitname, nfields, ifields, ifields_col));
351     }
352   }
353   if (i > 0) {
354     /* Makes command-line setting of splits take precedence over setting them in code.
355        Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would
356        create new splits, which would probably not be what the user wanted. */
357     jac->splitdefined = PETSC_TRUE;
358   }
359   PetscCall(PetscFree(ifields));
360   PetscCall(PetscFree(ifields_col));
361   PetscFunctionReturn(0);
362 }
363 
364 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) {
365   PC_FieldSplit    *jac                = (PC_FieldSplit *)pc->data;
366   PC_FieldSplitLink ilink              = jac->head;
367   PetscBool         fieldsplit_default = PETSC_FALSE, coupling = PETSC_FALSE;
368   PetscInt          i;
369 
370   PetscFunctionBegin;
371   /*
372    Kinda messy, but at least this now uses DMCreateFieldDecomposition().
373    Should probably be rewritten.
374    */
375   if (!ilink) {
376     PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_detect_coupling", &coupling, NULL));
377     if (pc->dm && jac->dm_splits && !jac->detect && !coupling) {
378       PetscInt  numFields, f, i, j;
379       char    **fieldNames;
380       IS       *fields;
381       DM       *dms;
382       DM        subdm[128];
383       PetscBool flg;
384 
385       PetscCall(DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms));
386       /* Allow the user to prescribe the splits */
387       for (i = 0, flg = PETSC_TRUE;; i++) {
388         PetscInt ifields[128];
389         IS       compField;
390         char     optionname[128], splitname[8];
391         PetscInt nfields = numFields;
392 
393         PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%" PetscInt_FMT "_fields", i));
394         PetscCall(PetscOptionsGetIntArray(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg));
395         if (!flg) break;
396         PetscCheck(numFields <= 128, PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Cannot currently support %" PetscInt_FMT " > 128 fields", numFields);
397         PetscCall(DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i]));
398         if (nfields == 1) {
399           PetscCall(PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField));
400         } else {
401           PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
402           PetscCall(PCFieldSplitSetIS(pc, splitname, compField));
403         }
404         PetscCall(ISDestroy(&compField));
405         for (j = 0; j < nfields; ++j) {
406           f = ifields[j];
407           PetscCall(PetscFree(fieldNames[f]));
408           PetscCall(ISDestroy(&fields[f]));
409         }
410       }
411       if (i == 0) {
412         for (f = 0; f < numFields; ++f) {
413           PetscCall(PCFieldSplitSetIS(pc, fieldNames[f], fields[f]));
414           PetscCall(PetscFree(fieldNames[f]));
415           PetscCall(ISDestroy(&fields[f]));
416         }
417       } else {
418         for (j = 0; j < numFields; j++) PetscCall(DMDestroy(dms + j));
419         PetscCall(PetscFree(dms));
420         PetscCall(PetscMalloc1(i, &dms));
421         for (j = 0; j < i; ++j) dms[j] = subdm[j];
422       }
423       PetscCall(PetscFree(fieldNames));
424       PetscCall(PetscFree(fields));
425       if (dms) {
426         PetscCall(PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n"));
427         for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) {
428           const char *prefix;
429           PetscCall(PetscObjectGetOptionsPrefix((PetscObject)(ilink->ksp), &prefix));
430           PetscCall(PetscObjectSetOptionsPrefix((PetscObject)(dms[i]), prefix));
431           PetscCall(KSPSetDM(ilink->ksp, dms[i]));
432           PetscCall(KSPSetDMActive(ilink->ksp, PETSC_FALSE));
433           {
434             PetscErrorCode (*func)(KSP, Mat, Mat, void *);
435             void *ctx;
436 
437             PetscCall(DMKSPGetComputeOperators(pc->dm, &func, &ctx));
438             PetscCall(DMKSPSetComputeOperators(dms[i], func, ctx));
439           }
440           PetscCall(PetscObjectIncrementTabLevel((PetscObject)dms[i], (PetscObject)ilink->ksp, 0));
441           PetscCall(DMDestroy(&dms[i]));
442         }
443         PetscCall(PetscFree(dms));
444       }
445     } else {
446       if (jac->bs <= 0) {
447         if (pc->pmat) {
448           PetscCall(MatGetBlockSize(pc->pmat, &jac->bs));
449         } else jac->bs = 1;
450       }
451 
452       if (jac->detect) {
453         IS       zerodiags, rest;
454         PetscInt nmin, nmax;
455 
456         PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
457         if (jac->diag_use_amat) {
458           PetscCall(MatFindZeroDiagonals(pc->mat, &zerodiags));
459         } else {
460           PetscCall(MatFindZeroDiagonals(pc->pmat, &zerodiags));
461         }
462         PetscCall(ISComplement(zerodiags, nmin, nmax, &rest));
463         PetscCall(PCFieldSplitSetIS(pc, "0", rest));
464         PetscCall(PCFieldSplitSetIS(pc, "1", zerodiags));
465         PetscCall(ISDestroy(&zerodiags));
466         PetscCall(ISDestroy(&rest));
467       } else if (coupling) {
468         IS       coupling, rest;
469         PetscInt nmin, nmax;
470 
471         PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
472         if (jac->offdiag_use_amat) {
473           PetscCall(MatFindOffBlockDiagonalEntries(pc->mat, &coupling));
474         } else {
475           PetscCall(MatFindOffBlockDiagonalEntries(pc->pmat, &coupling));
476         }
477         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc->mat), nmax - nmin, nmin, 1, &rest));
478         PetscCall(ISSetIdentity(rest));
479         PetscCall(PCFieldSplitSetIS(pc, "0", rest));
480         PetscCall(PCFieldSplitSetIS(pc, "1", coupling));
481         PetscCall(ISDestroy(&coupling));
482         PetscCall(ISDestroy(&rest));
483       } else {
484         PetscCall(PetscOptionsGetBool(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_default", &fieldsplit_default, NULL));
485         if (!fieldsplit_default) {
486           /* Allow user to set fields from command line,  if bs was known at the time of PCSetFromOptions_FieldSplit()
487            then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
488           PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc));
489           if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n"));
490         }
491         if ((fieldsplit_default || !jac->splitdefined) && !jac->isrestrict) {
492           Mat       M = pc->pmat;
493           PetscBool isnest;
494 
495           PetscCall(PetscInfo(pc, "Using default splitting of fields\n"));
496           PetscCall(PetscObjectTypeCompare((PetscObject)pc->pmat, MATNEST, &isnest));
497           if (!isnest) {
498             M = pc->mat;
499             PetscCall(PetscObjectTypeCompare((PetscObject)pc->mat, MATNEST, &isnest));
500           }
501           if (isnest) {
502             IS      *fields;
503             PetscInt nf;
504 
505             PetscCall(MatNestGetSize(M, &nf, NULL));
506             PetscCall(PetscMalloc1(nf, &fields));
507             PetscCall(MatNestGetISs(M, fields, NULL));
508             for (i = 0; i < nf; i++) PetscCall(PCFieldSplitSetIS(pc, NULL, fields[i]));
509             PetscCall(PetscFree(fields));
510           } else {
511             for (i = 0; i < jac->bs; i++) {
512               char splitname[8];
513               PetscCall(PetscSNPrintf(splitname, sizeof(splitname), "%" PetscInt_FMT, i));
514               PetscCall(PCFieldSplitSetFields(pc, splitname, 1, &i, &i));
515             }
516             jac->defaultsplit = PETSC_TRUE;
517           }
518         }
519       }
520     }
521   } else if (jac->nsplits == 1) {
522     if (ilink->is) {
523       IS       is2;
524       PetscInt nmin, nmax;
525 
526       PetscCall(MatGetOwnershipRange(pc->mat, &nmin, &nmax));
527       PetscCall(ISComplement(ilink->is, nmin, nmax, &is2));
528       PetscCall(PCFieldSplitSetIS(pc, "1", is2));
529       PetscCall(ISDestroy(&is2));
530     } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Must provide at least two sets of fields to PCFieldSplit()");
531   }
532 
533   PetscCheck(jac->nsplits >= 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unhandled case, must have at least two fields, not %" PetscInt_FMT, jac->nsplits);
534   PetscFunctionReturn(0);
535 }
536 
537 static PetscErrorCode MatGolubKahanComputeExplicitOperator(Mat A, Mat B, Mat C, Mat *H, PetscReal gkbnu) {
538   Mat       BT, T;
539   PetscReal nrmT, nrmB;
540 
541   PetscFunctionBegin;
542   PetscCall(MatHermitianTranspose(C, MAT_INITIAL_MATRIX, &T)); /* Test if augmented matrix is symmetric */
543   PetscCall(MatAXPY(T, -1.0, B, DIFFERENT_NONZERO_PATTERN));
544   PetscCall(MatNorm(T, NORM_1, &nrmT));
545   PetscCall(MatNorm(B, NORM_1, &nrmB));
546   PetscCheck(nrmB <= 0 || nrmT / nrmB < PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Matrix is not symmetric/hermitian, GKB is not applicable.");
547 
548   /* Compute augmented Lagrangian matrix H = A00 + nu*A01*A01'. This corresponds to */
549   /* setting N := 1/nu*I in [Ar13].                                                 */
550   PetscCall(MatHermitianTranspose(B, MAT_INITIAL_MATRIX, &BT));
551   PetscCall(MatMatMult(B, BT, MAT_INITIAL_MATRIX, PETSC_DEFAULT, H)); /* H = A01*A01'          */
552   PetscCall(MatAYPX(*H, gkbnu, A, DIFFERENT_NONZERO_PATTERN));        /* H = A00 + nu*A01*A01' */
553 
554   PetscCall(MatDestroy(&BT));
555   PetscCall(MatDestroy(&T));
556   PetscFunctionReturn(0);
557 }
558 
559 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions, const char pre[], const char name[], const char *value[], PetscBool *flg);
560 
561 static PetscErrorCode PCSetUp_FieldSplit(PC pc) {
562   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
563   PC_FieldSplitLink ilink;
564   PetscInt          i, nsplit;
565   PetscBool         sorted, sorted_col;
566 
567   PetscFunctionBegin;
568   pc->failedreason = PC_NOERROR;
569   PetscCall(PCFieldSplitSetDefaults(pc));
570   nsplit = jac->nsplits;
571   ilink  = jac->head;
572 
573   /* get the matrices for each split */
574   if (!jac->issetup) {
575     PetscInt rstart, rend, nslots, bs;
576 
577     jac->issetup = PETSC_TRUE;
578 
579     /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
580     if (jac->defaultsplit || !ilink->is) {
581       if (jac->bs <= 0) jac->bs = nsplit;
582     }
583     bs = jac->bs;
584     PetscCall(MatGetOwnershipRange(pc->pmat, &rstart, &rend));
585     nslots = (rend - rstart) / bs;
586     for (i = 0; i < nsplit; i++) {
587       if (jac->defaultsplit) {
588         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + i, nsplit, &ilink->is));
589         PetscCall(ISDuplicate(ilink->is, &ilink->is_col));
590       } else if (!ilink->is) {
591         if (ilink->nfields > 1) {
592           PetscInt *ii, *jj, j, k, nfields = ilink->nfields, *fields = ilink->fields, *fields_col = ilink->fields_col;
593           PetscCall(PetscMalloc1(ilink->nfields * nslots, &ii));
594           PetscCall(PetscMalloc1(ilink->nfields * nslots, &jj));
595           for (j = 0; j < nslots; j++) {
596             for (k = 0; k < nfields; k++) {
597               ii[nfields * j + k] = rstart + bs * j + fields[k];
598               jj[nfields * j + k] = rstart + bs * j + fields_col[k];
599             }
600           }
601           PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nslots * nfields, ii, PETSC_OWN_POINTER, &ilink->is));
602           PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)pc), nslots * nfields, jj, PETSC_OWN_POINTER, &ilink->is_col));
603           PetscCall(ISSetBlockSize(ilink->is, nfields));
604           PetscCall(ISSetBlockSize(ilink->is_col, nfields));
605         } else {
606           PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + ilink->fields[0], bs, &ilink->is));
607           PetscCall(ISCreateStride(PetscObjectComm((PetscObject)pc), nslots, rstart + ilink->fields_col[0], bs, &ilink->is_col));
608         }
609       }
610       PetscCall(ISSorted(ilink->is, &sorted));
611       if (ilink->is_col) PetscCall(ISSorted(ilink->is_col, &sorted_col));
612       PetscCheck(sorted && sorted_col, PETSC_COMM_SELF, PETSC_ERR_USER, "Fields must be sorted when creating split");
613       ilink = ilink->next;
614     }
615   }
616 
617   ilink = jac->head;
618   if (!jac->pmat) {
619     Vec xtmp;
620 
621     PetscCall(MatCreateVecs(pc->pmat, &xtmp, NULL));
622     PetscCall(PetscMalloc1(nsplit, &jac->pmat));
623     PetscCall(PetscMalloc2(nsplit, &jac->x, nsplit, &jac->y));
624     for (i = 0; i < nsplit; i++) {
625       MatNullSpace sp;
626 
627       /* Check for preconditioning matrix attached to IS */
628       PetscCall(PetscObjectQuery((PetscObject)ilink->is, "pmat", (PetscObject *)&jac->pmat[i]));
629       if (jac->pmat[i]) {
630         PetscCall(PetscObjectReference((PetscObject)jac->pmat[i]));
631         if (jac->type == PC_COMPOSITE_SCHUR) {
632           jac->schur_user = jac->pmat[i];
633 
634           PetscCall(PetscObjectReference((PetscObject)jac->schur_user));
635         }
636       } else {
637         const char *prefix;
638         PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ilink->is_col, MAT_INITIAL_MATRIX, &jac->pmat[i]));
639         PetscCall(KSPGetOptionsPrefix(ilink->ksp, &prefix));
640         PetscCall(MatSetOptionsPrefix(jac->pmat[i], prefix));
641         PetscCall(MatViewFromOptions(jac->pmat[i], NULL, "-mat_view"));
642       }
643       /* create work vectors for each split */
644       PetscCall(MatCreateVecs(jac->pmat[i], &jac->x[i], &jac->y[i]));
645       ilink->x = jac->x[i];
646       ilink->y = jac->y[i];
647       ilink->z = NULL;
648       /* compute scatter contexts needed by multiplicative versions and non-default splits */
649       PetscCall(VecScatterCreate(xtmp, ilink->is, jac->x[i], NULL, &ilink->sctx));
650       PetscCall(PetscObjectQuery((PetscObject)ilink->is, "nearnullspace", (PetscObject *)&sp));
651       if (sp) PetscCall(MatSetNearNullSpace(jac->pmat[i], sp));
652       ilink = ilink->next;
653     }
654     PetscCall(VecDestroy(&xtmp));
655   } else {
656     MatReuse scall;
657     if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
658       for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->pmat[i]));
659       scall = MAT_INITIAL_MATRIX;
660     } else scall = MAT_REUSE_MATRIX;
661 
662     for (i = 0; i < nsplit; i++) {
663       Mat pmat;
664 
665       /* Check for preconditioning matrix attached to IS */
666       PetscCall(PetscObjectQuery((PetscObject)ilink->is, "pmat", (PetscObject *)&pmat));
667       if (!pmat) PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ilink->is_col, scall, &jac->pmat[i]));
668       ilink = ilink->next;
669     }
670   }
671   if (jac->diag_use_amat) {
672     ilink = jac->head;
673     if (!jac->mat) {
674       PetscCall(PetscMalloc1(nsplit, &jac->mat));
675       for (i = 0; i < nsplit; i++) {
676         PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ilink->is_col, MAT_INITIAL_MATRIX, &jac->mat[i]));
677         ilink = ilink->next;
678       }
679     } else {
680       MatReuse scall;
681       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
682         for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->mat[i]));
683         scall = MAT_INITIAL_MATRIX;
684       } else scall = MAT_REUSE_MATRIX;
685 
686       for (i = 0; i < nsplit; i++) {
687         PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ilink->is_col, scall, &jac->mat[i]));
688         ilink = ilink->next;
689       }
690     }
691   } else {
692     jac->mat = jac->pmat;
693   }
694 
695   /* Check for null space attached to IS */
696   ilink = jac->head;
697   for (i = 0; i < nsplit; i++) {
698     MatNullSpace sp;
699 
700     PetscCall(PetscObjectQuery((PetscObject)ilink->is, "nullspace", (PetscObject *)&sp));
701     if (sp) PetscCall(MatSetNullSpace(jac->mat[i], sp));
702     ilink = ilink->next;
703   }
704 
705   if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR && jac->type != PC_COMPOSITE_GKB) {
706     /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
707     /* FIXME: Can/should we reuse jac->mat whenever (jac->diag_use_amat) is true? */
708     ilink = jac->head;
709     if (nsplit == 2 && jac->type == PC_COMPOSITE_MULTIPLICATIVE) {
710       /* 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 */
711       if (!jac->Afield) {
712         PetscCall(PetscCalloc1(nsplit, &jac->Afield));
713         if (jac->offdiag_use_amat) {
714           PetscCall(MatCreateSubMatrix(pc->mat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->Afield[1]));
715         } else {
716           PetscCall(MatCreateSubMatrix(pc->pmat, ilink->next->is, ilink->is, MAT_INITIAL_MATRIX, &jac->Afield[1]));
717         }
718       } else {
719         MatReuse scall;
720 
721         if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
722           PetscCall(MatDestroy(&jac->Afield[1]));
723           scall = MAT_INITIAL_MATRIX;
724         } else scall = MAT_REUSE_MATRIX;
725 
726         if (jac->offdiag_use_amat) {
727           PetscCall(MatCreateSubMatrix(pc->mat, ilink->next->is, ilink->is, scall, &jac->Afield[1]));
728         } else {
729           PetscCall(MatCreateSubMatrix(pc->pmat, ilink->next->is, ilink->is, scall, &jac->Afield[1]));
730         }
731       }
732     } else {
733       if (!jac->Afield) {
734         PetscCall(PetscMalloc1(nsplit, &jac->Afield));
735         for (i = 0; i < nsplit; i++) {
736           if (jac->offdiag_use_amat) {
737             PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, NULL, MAT_INITIAL_MATRIX, &jac->Afield[i]));
738           } else {
739             PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, NULL, MAT_INITIAL_MATRIX, &jac->Afield[i]));
740           }
741           ilink = ilink->next;
742         }
743       } else {
744         MatReuse scall;
745         if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
746           for (i = 0; i < nsplit; i++) PetscCall(MatDestroy(&jac->Afield[i]));
747           scall = MAT_INITIAL_MATRIX;
748         } else scall = MAT_REUSE_MATRIX;
749 
750         for (i = 0; i < nsplit; i++) {
751           if (jac->offdiag_use_amat) {
752             PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, NULL, scall, &jac->Afield[i]));
753           } else {
754             PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, NULL, scall, &jac->Afield[i]));
755           }
756           ilink = ilink->next;
757         }
758       }
759     }
760   }
761 
762   if (jac->type == PC_COMPOSITE_SCHUR) {
763     IS          ccis;
764     PetscBool   isset, isspd;
765     PetscInt    rstart, rend;
766     char        lscname[256];
767     PetscObject LSC_L;
768 
769     PetscCheck(nsplit == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "To use Schur complement preconditioner you must have exactly 2 fields");
770 
771     /* If pc->mat is SPD, don't scale by -1 the Schur complement */
772     if (jac->schurscale == (PetscScalar)-1.0) {
773       PetscCall(MatIsSPDKnown(pc->pmat, &isset, &isspd));
774       jac->schurscale = (isset && isspd) ? 1.0 : -1.0;
775     }
776 
777     /* When extracting off-diagonal submatrices, we take complements from this range */
778     PetscCall(MatGetOwnershipRangeColumn(pc->mat, &rstart, &rend));
779 
780     if (jac->schur) {
781       KSP      kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper;
782       MatReuse scall;
783 
784       if (pc->flag == DIFFERENT_NONZERO_PATTERN) {
785         scall = MAT_INITIAL_MATRIX;
786         PetscCall(MatDestroy(&jac->B));
787         PetscCall(MatDestroy(&jac->C));
788       } else scall = MAT_REUSE_MATRIX;
789 
790       PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
791       ilink = jac->head;
792       PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis));
793       if (jac->offdiag_use_amat) {
794         PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, scall, &jac->B));
795       } else {
796         PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, scall, &jac->B));
797       }
798       PetscCall(ISDestroy(&ccis));
799       ilink = ilink->next;
800       PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis));
801       if (jac->offdiag_use_amat) {
802         PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, scall, &jac->C));
803       } else {
804         PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, scall, &jac->C));
805       }
806       PetscCall(ISDestroy(&ccis));
807       PetscCall(MatSchurComplementUpdateSubMatrices(jac->schur, jac->mat[0], jac->pmat[0], jac->B, jac->C, jac->mat[1]));
808       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) {
809         PetscCall(MatDestroy(&jac->schurp));
810         PetscCall(MatSchurComplementGetPmat(jac->schur, MAT_INITIAL_MATRIX, &jac->schurp));
811       }
812       if (kspA != kspInner) PetscCall(KSPSetOperators(kspA, jac->mat[0], jac->pmat[0]));
813       if (kspUpper != kspA) PetscCall(KSPSetOperators(kspUpper, jac->mat[0], jac->pmat[0]));
814       PetscCall(KSPSetOperators(jac->kspschur, jac->schur, FieldSplitSchurPre(jac)));
815     } else {
816       const char  *Dprefix;
817       char         schurprefix[256], schurmatprefix[256];
818       char         schurtestoption[256];
819       MatNullSpace sp;
820       PetscBool    flg;
821       KSP          kspt;
822 
823       /* extract the A01 and A10 matrices */
824       ilink = jac->head;
825       PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis));
826       if (jac->offdiag_use_amat) {
827         PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->B));
828       } else {
829         PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->B));
830       }
831       PetscCall(ISDestroy(&ccis));
832       ilink = ilink->next;
833       PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis));
834       if (jac->offdiag_use_amat) {
835         PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->C));
836       } else {
837         PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->C));
838       }
839       PetscCall(ISDestroy(&ccis));
840 
841       /* Use mat[0] (diagonal block of Amat) preconditioned by pmat[0] to define Schur complement */
842       PetscCall(MatCreate(((PetscObject)jac->mat[0])->comm, &jac->schur));
843       PetscCall(MatSetType(jac->schur, MATSCHURCOMPLEMENT));
844       PetscCall(MatSchurComplementSetSubMatrices(jac->schur, jac->mat[0], jac->pmat[0], jac->B, jac->C, jac->mat[1]));
845       PetscCall(PetscSNPrintf(schurmatprefix, sizeof(schurmatprefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
846       PetscCall(MatSetOptionsPrefix(jac->schur, schurmatprefix));
847       PetscCall(MatSchurComplementGetKSP(jac->schur, &kspt));
848       PetscCall(KSPSetOptionsPrefix(kspt, schurmatprefix));
849 
850       /* Note: this is not true in general */
851       PetscCall(MatGetNullSpace(jac->mat[1], &sp));
852       if (sp) PetscCall(MatSetNullSpace(jac->schur, sp));
853 
854       PetscCall(PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname));
855       PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, schurtestoption, NULL, &flg));
856       if (flg) {
857         DM  dmInner;
858         KSP kspInner;
859         PC  pcInner;
860 
861         PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
862         PetscCall(KSPReset(kspInner));
863         PetscCall(KSPSetOperators(kspInner, jac->mat[0], jac->pmat[0]));
864         PetscCall(PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
865         /* Indent this deeper to emphasize the "inner" nature of this solver. */
866         PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspInner, (PetscObject)pc, 2));
867         PetscCall(PetscObjectIncrementTabLevel((PetscObject)kspInner->pc, (PetscObject)pc, 2));
868         PetscCall(KSPSetOptionsPrefix(kspInner, schurprefix));
869 
870         /* Set DM for new solver */
871         PetscCall(KSPGetDM(jac->head->ksp, &dmInner));
872         PetscCall(KSPSetDM(kspInner, dmInner));
873         PetscCall(KSPSetDMActive(kspInner, PETSC_FALSE));
874 
875         /* Defaults to PCKSP as preconditioner */
876         PetscCall(KSPGetPC(kspInner, &pcInner));
877         PetscCall(PCSetType(pcInner, PCKSP));
878         PetscCall(PCKSPSetKSP(pcInner, jac->head->ksp));
879       } else {
880         /* Use the outer solver for the inner solve, but revert the KSPPREONLY from PCFieldSplitSetFields_FieldSplit or
881           * PCFieldSplitSetIS_FieldSplit. We don't want KSPPREONLY because it makes the Schur complement inexact,
882           * preventing Schur complement reduction to be an accurate solve. Usually when an iterative solver is used for
883           * S = D - C A_inner^{-1} B, we expect S to be defined using an accurate definition of A_inner^{-1}, so we make
884           * GMRES the default. Note that it is also common to use PREONLY for S, in which case S may not be used
885           * directly, and the user is responsible for setting an inexact method for fieldsplit's A^{-1}. */
886         PetscCall(KSPSetType(jac->head->ksp, KSPGMRES));
887         PetscCall(MatSchurComplementSetKSP(jac->schur, jac->head->ksp));
888       }
889       PetscCall(KSPSetOperators(jac->head->ksp, jac->mat[0], jac->pmat[0]));
890       PetscCall(KSPSetFromOptions(jac->head->ksp));
891       PetscCall(MatSetFromOptions(jac->schur));
892 
893       PetscCall(PetscObjectTypeCompare((PetscObject)jac->schur, MATSCHURCOMPLEMENT, &flg));
894       if (flg) { /* Need to do this otherwise PCSetUp_KSP will overwrite the amat of jac->head->ksp */
895         KSP kspInner;
896         PC  pcInner;
897 
898         PetscCall(MatSchurComplementGetKSP(jac->schur, &kspInner));
899         PetscCall(KSPGetPC(kspInner, &pcInner));
900         PetscCall(PetscObjectTypeCompare((PetscObject)pcInner, PCKSP, &flg));
901         if (flg) {
902           KSP ksp;
903 
904           PetscCall(PCKSPGetKSP(pcInner, &ksp));
905           if (ksp == jac->head->ksp) PetscCall(PCSetUseAmat(pcInner, PETSC_TRUE));
906         }
907       }
908       PetscCall(PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname));
909       PetscCall(PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, schurtestoption, NULL, &flg));
910       if (flg) {
911         DM dmInner;
912 
913         PetscCall(PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
914         PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspupper));
915         PetscCall(KSPSetErrorIfNotConverged(jac->kspupper, pc->erroriffailure));
916         PetscCall(KSPSetOptionsPrefix(jac->kspupper, schurprefix));
917         PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspupper, (PetscObject)pc, 1));
918         PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspupper->pc, (PetscObject)pc, 1));
919         PetscCall(KSPGetDM(jac->head->ksp, &dmInner));
920         PetscCall(KSPSetDM(jac->kspupper, dmInner));
921         PetscCall(KSPSetDMActive(jac->kspupper, PETSC_FALSE));
922         PetscCall(KSPSetFromOptions(jac->kspupper));
923         PetscCall(KSPSetOperators(jac->kspupper, jac->mat[0], jac->pmat[0]));
924         PetscCall(VecDuplicate(jac->head->x, &jac->head->z));
925       } else {
926         jac->kspupper = jac->head->ksp;
927         PetscCall(PetscObjectReference((PetscObject)jac->head->ksp));
928       }
929 
930       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) PetscCall(MatSchurComplementGetPmat(jac->schur, MAT_INITIAL_MATRIX, &jac->schurp));
931       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspschur));
932       PetscCall(KSPSetErrorIfNotConverged(jac->kspschur, pc->erroriffailure));
933       PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)jac->kspschur));
934       PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspschur, (PetscObject)pc, 1));
935       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
936         PC pcschur;
937         PetscCall(KSPGetPC(jac->kspschur, &pcschur));
938         PetscCall(PCSetType(pcschur, PCNONE));
939         /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
940       } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL) {
941         PetscCall(MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user));
942       }
943       PetscCall(KSPSetOperators(jac->kspschur, jac->schur, FieldSplitSchurPre(jac)));
944       PetscCall(KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix));
945       PetscCall(KSPSetOptionsPrefix(jac->kspschur, Dprefix));
946       /* propagate DM */
947       {
948         DM sdm;
949         PetscCall(KSPGetDM(jac->head->next->ksp, &sdm));
950         if (sdm) {
951           PetscCall(KSPSetDM(jac->kspschur, sdm));
952           PetscCall(KSPSetDMActive(jac->kspschur, PETSC_FALSE));
953         }
954       }
955       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
956       /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */
957       PetscCall(KSPSetFromOptions(jac->kspschur));
958     }
959     PetscCall(MatAssemblyBegin(jac->schur, MAT_FINAL_ASSEMBLY));
960     PetscCall(MatAssemblyEnd(jac->schur, MAT_FINAL_ASSEMBLY));
961 
962     /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */
963     PetscCall(PetscSNPrintf(lscname, sizeof(lscname), "%s_LSC_L", ilink->splitname));
964     PetscCall(PetscObjectQuery((PetscObject)pc->mat, lscname, (PetscObject *)&LSC_L));
965     if (!LSC_L) PetscCall(PetscObjectQuery((PetscObject)pc->pmat, lscname, (PetscObject *)&LSC_L));
966     if (LSC_L) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "LSC_L", (PetscObject)LSC_L));
967     PetscCall(PetscSNPrintf(lscname, sizeof(lscname), "%s_LSC_Lp", ilink->splitname));
968     PetscCall(PetscObjectQuery((PetscObject)pc->pmat, lscname, (PetscObject *)&LSC_L));
969     if (!LSC_L) PetscCall(PetscObjectQuery((PetscObject)pc->mat, lscname, (PetscObject *)&LSC_L));
970     if (LSC_L) PetscCall(PetscObjectCompose((PetscObject)jac->schur, "LSC_Lp", (PetscObject)LSC_L));
971   } else if (jac->type == PC_COMPOSITE_GKB) {
972     IS       ccis;
973     PetscInt rstart, rend;
974 
975     PetscCheck(nsplit == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_INCOMP, "To use GKB preconditioner you must have exactly 2 fields");
976 
977     ilink = jac->head;
978 
979     /* When extracting off-diagonal submatrices, we take complements from this range */
980     PetscCall(MatGetOwnershipRangeColumn(pc->mat, &rstart, &rend));
981 
982     PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis));
983     if (jac->offdiag_use_amat) {
984       PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->B));
985     } else {
986       PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->B));
987     }
988     PetscCall(ISDestroy(&ccis));
989     /* Create work vectors for GKB algorithm */
990     PetscCall(VecDuplicate(ilink->x, &jac->u));
991     PetscCall(VecDuplicate(ilink->x, &jac->Hu));
992     PetscCall(VecDuplicate(ilink->x, &jac->w2));
993     ilink = ilink->next;
994     PetscCall(ISComplement(ilink->is_col, rstart, rend, &ccis));
995     if (jac->offdiag_use_amat) {
996       PetscCall(MatCreateSubMatrix(pc->mat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->C));
997     } else {
998       PetscCall(MatCreateSubMatrix(pc->pmat, ilink->is, ccis, MAT_INITIAL_MATRIX, &jac->C));
999     }
1000     PetscCall(ISDestroy(&ccis));
1001     /* Create work vectors for GKB algorithm */
1002     PetscCall(VecDuplicate(ilink->x, &jac->v));
1003     PetscCall(VecDuplicate(ilink->x, &jac->d));
1004     PetscCall(VecDuplicate(ilink->x, &jac->w1));
1005     PetscCall(MatGolubKahanComputeExplicitOperator(jac->mat[0], jac->B, jac->C, &jac->H, jac->gkbnu));
1006     PetscCall(PetscCalloc1(jac->gkbdelay, &jac->vecz));
1007 
1008     ilink = jac->head;
1009     PetscCall(KSPSetOperators(ilink->ksp, jac->H, jac->H));
1010     if (!jac->suboptionsset) PetscCall(KSPSetFromOptions(ilink->ksp));
1011     /* Create gkb_monitor context */
1012     if (jac->gkbmonitor) {
1013       PetscInt tablevel;
1014       PetscCall(PetscViewerCreate(PETSC_COMM_WORLD, &jac->gkbviewer));
1015       PetscCall(PetscViewerSetType(jac->gkbviewer, PETSCVIEWERASCII));
1016       PetscCall(PetscObjectGetTabLevel((PetscObject)ilink->ksp, &tablevel));
1017       PetscCall(PetscViewerASCIISetTab(jac->gkbviewer, tablevel));
1018       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)ilink->ksp, 1));
1019     }
1020   } else {
1021     /* set up the individual splits' PCs */
1022     i     = 0;
1023     ilink = jac->head;
1024     while (ilink) {
1025       PetscCall(KSPSetOperators(ilink->ksp, jac->mat[i], jac->pmat[i]));
1026       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
1027       if (!jac->suboptionsset) PetscCall(KSPSetFromOptions(ilink->ksp));
1028       i++;
1029       ilink = ilink->next;
1030     }
1031   }
1032 
1033   /* Set coordinates to the sub PC objects whenever these are set */
1034   if (jac->coordinates_set) {
1035     PC pc_coords;
1036     if (jac->type == PC_COMPOSITE_SCHUR) {
1037       // Head is first block.
1038       PetscCall(KSPGetPC(jac->head->ksp, &pc_coords));
1039       PetscCall(PCSetCoordinates(pc_coords, jac->head->dim, jac->head->ndofs, jac->head->coords));
1040       // Second one is Schur block, but its KSP object is in kspschur.
1041       PetscCall(KSPGetPC(jac->kspschur, &pc_coords));
1042       PetscCall(PCSetCoordinates(pc_coords, jac->head->next->dim, jac->head->next->ndofs, jac->head->next->coords));
1043     } else if (jac->type == PC_COMPOSITE_GKB) {
1044       PetscCall(PetscInfo(pc, "Warning: Setting coordinates does nothing for the GKB Fieldpslit preconditioner"));
1045     } else {
1046       ilink = jac->head;
1047       while (ilink) {
1048         PetscCall(KSPGetPC(ilink->ksp, &pc_coords));
1049         PetscCall(PCSetCoordinates(pc_coords, ilink->dim, ilink->ndofs, ilink->coords));
1050         ilink = ilink->next;
1051       }
1052     }
1053   }
1054 
1055   jac->suboptionsset = PETSC_TRUE;
1056   PetscFunctionReturn(0);
1057 }
1058 
1059 #define FieldSplitSplitSolveAdd(ilink, xx, yy) \
1060   (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) || \
1061    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) || \
1062    VecScatterEnd(ilink->sctx, ilink->y, yy, ADD_VALUES, SCATTER_REVERSE))
1063 
1064 static PetscErrorCode PCApply_FieldSplit_Schur(PC pc, Vec x, Vec y) {
1065   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
1066   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1067   KSP               kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;
1068 
1069   PetscFunctionBegin;
1070   switch (jac->schurfactorization) {
1071   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
1072     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
1073     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
1074     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1075     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
1076     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1077     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
1078     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
1079     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1080     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1081     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1082     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1083     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1084     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
1085     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1086     PetscCall(VecScale(ilinkD->y, jac->schurscale));
1087     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1088     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1089     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1090     break;
1091   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
1092     /* [A00 0; A10 S], suitable for left preconditioning */
1093     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
1094     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
1095     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1096     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
1097     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
1098     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1099     PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x));
1100     PetscCall(VecScale(ilinkD->x, -1.));
1101     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
1102     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1103     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
1104     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1105     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1106     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
1107     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1108     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1109     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1110     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1111     break;
1112   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
1113     /* [A00 A01; 0 S], suitable for right preconditioning */
1114     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1115     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1116     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1117     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1118     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
1119     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1120     PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x));
1121     PetscCall(VecScale(ilinkA->x, -1.));
1122     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
1123     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1124     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, ADD_VALUES, SCATTER_FORWARD));
1125     PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1126     PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
1127     PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
1128     PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1129     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1130     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1131     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1132     break;
1133   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
1134     /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */
1135     PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
1136     PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
1137     PetscCall(PetscLogEventBegin(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL));
1138     PetscCall(KSPSolve(kspLower, ilinkA->x, ilinkA->y));
1139     PetscCall(KSPCheckSolve(kspLower, pc, ilinkA->y));
1140     PetscCall(PetscLogEventEnd(KSP_Solve_FS_L, kspLower, ilinkA->x, ilinkA->y, NULL));
1141     PetscCall(MatMult(jac->C, ilinkA->y, ilinkD->x));
1142     PetscCall(VecScale(ilinkD->x, -1.0));
1143     PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
1144     PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, ADD_VALUES, SCATTER_FORWARD));
1145 
1146     PetscCall(PetscLogEventBegin(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1147     PetscCall(KSPSolve(jac->kspschur, ilinkD->x, ilinkD->y));
1148     PetscCall(KSPCheckSolve(jac->kspschur, pc, ilinkD->y));
1149     PetscCall(PetscLogEventEnd(KSP_Solve_FS_S, jac->kspschur, ilinkD->x, ilinkD->y, NULL));
1150     PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1151 
1152     if (kspUpper == kspA) {
1153       PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->y));
1154       PetscCall(VecAXPY(ilinkA->x, -1.0, ilinkA->y));
1155       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1156       PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
1157       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
1158       PetscCall(PetscLogEventEnd(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1159     } else {
1160       PetscCall(PetscLogEventBegin(ilinkA->event, kspA, ilinkA->x, ilinkA->y, NULL));
1161       PetscCall(KSPSolve(kspA, ilinkA->x, ilinkA->y));
1162       PetscCall(KSPCheckSolve(kspA, pc, ilinkA->y));
1163       PetscCall(MatMult(jac->B, ilinkD->y, ilinkA->x));
1164       PetscCall(PetscLogEventBegin(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL));
1165       PetscCall(KSPSolve(kspUpper, ilinkA->x, ilinkA->z));
1166       PetscCall(KSPCheckSolve(kspUpper, pc, ilinkA->z));
1167       PetscCall(PetscLogEventEnd(KSP_Solve_FS_U, kspUpper, ilinkA->x, ilinkA->z, NULL));
1168       PetscCall(VecAXPY(ilinkA->y, -1.0, ilinkA->z));
1169     }
1170     PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1171     PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1172     PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1173   }
1174   PetscFunctionReturn(0);
1175 }
1176 
1177 static PetscErrorCode PCApply_FieldSplit(PC pc, Vec x, Vec y) {
1178   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1179   PC_FieldSplitLink ilink = jac->head;
1180   PetscInt          cnt, bs;
1181 
1182   PetscFunctionBegin;
1183   if (jac->type == PC_COMPOSITE_ADDITIVE) {
1184     if (jac->defaultsplit) {
1185       PetscCall(VecGetBlockSize(x, &bs));
1186       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);
1187       PetscCall(VecGetBlockSize(y, &bs));
1188       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);
1189       PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
1190       while (ilink) {
1191         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1192         PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
1193         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
1194         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1195         ilink = ilink->next;
1196       }
1197       PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
1198     } else {
1199       PetscCall(VecSet(y, 0.0));
1200       while (ilink) {
1201         PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
1202         ilink = ilink->next;
1203       }
1204     }
1205   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
1206     PetscCall(VecSet(y, 0.0));
1207     /* solve on first block for first block variables */
1208     PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
1209     PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, INSERT_VALUES, SCATTER_FORWARD));
1210     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1211     PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
1212     PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
1213     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1214     PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1215     PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1216 
1217     /* compute the residual only onto second block variables using first block variables */
1218     PetscCall(MatMult(jac->Afield[1], ilink->y, ilink->next->x));
1219     ilink = ilink->next;
1220     PetscCall(VecScale(ilink->x, -1.0));
1221     PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1222     PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1223 
1224     /* solve on second block variables */
1225     PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1226     PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
1227     PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
1228     PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1229     PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1230     PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1231   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1232     if (!jac->w1) {
1233       PetscCall(VecDuplicate(x, &jac->w1));
1234       PetscCall(VecDuplicate(x, &jac->w2));
1235     }
1236     PetscCall(VecSet(y, 0.0));
1237     PetscCall(FieldSplitSplitSolveAdd(ilink, x, y));
1238     cnt = 1;
1239     while (ilink->next) {
1240       ilink = ilink->next;
1241       /* compute the residual only over the part of the vector needed */
1242       PetscCall(MatMult(jac->Afield[cnt++], y, ilink->x));
1243       PetscCall(VecScale(ilink->x, -1.0));
1244       PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1245       PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1246       PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1247       PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
1248       PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
1249       PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1250       PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1251       PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1252     }
1253     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1254       cnt -= 2;
1255       while (ilink->previous) {
1256         ilink = ilink->previous;
1257         /* compute the residual only over the part of the vector needed */
1258         PetscCall(MatMult(jac->Afield[cnt--], y, ilink->x));
1259         PetscCall(VecScale(ilink->x, -1.0));
1260         PetscCall(VecScatterBegin(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1261         PetscCall(VecScatterEnd(ilink->sctx, x, ilink->x, ADD_VALUES, SCATTER_FORWARD));
1262         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1263         PetscCall(KSPSolve(ilink->ksp, ilink->x, ilink->y));
1264         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
1265         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1266         PetscCall(VecScatterBegin(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1267         PetscCall(VecScatterEnd(ilink->sctx, ilink->y, y, ADD_VALUES, SCATTER_REVERSE));
1268       }
1269     }
1270   } else SETERRQ(PetscObjectComm((PetscObject)pc), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)jac->type);
1271   PetscFunctionReturn(0);
1272 }
1273 
1274 static PetscErrorCode PCApply_FieldSplit_GKB(PC pc, Vec x, Vec y) {
1275   PC_FieldSplit    *jac    = (PC_FieldSplit *)pc->data;
1276   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
1277   KSP               ksp = ilinkA->ksp;
1278   Vec               u, v, Hu, d, work1, work2;
1279   PetscScalar       alpha, z, nrmz2, *vecz;
1280   PetscReal         lowbnd, nu, beta;
1281   PetscInt          j, iterGKB;
1282 
1283   PetscFunctionBegin;
1284   PetscCall(VecScatterBegin(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
1285   PetscCall(VecScatterBegin(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1286   PetscCall(VecScatterEnd(ilinkA->sctx, x, ilinkA->x, INSERT_VALUES, SCATTER_FORWARD));
1287   PetscCall(VecScatterEnd(ilinkD->sctx, x, ilinkD->x, INSERT_VALUES, SCATTER_FORWARD));
1288 
1289   u     = jac->u;
1290   v     = jac->v;
1291   Hu    = jac->Hu;
1292   d     = jac->d;
1293   work1 = jac->w1;
1294   work2 = jac->w2;
1295   vecz  = jac->vecz;
1296 
1297   /* Change RHS to comply with matrix regularization H = A + nu*B*B' */
1298   /* Add q = q + nu*B*b */
1299   if (jac->gkbnu) {
1300     nu = jac->gkbnu;
1301     PetscCall(VecScale(ilinkD->x, jac->gkbnu));
1302     PetscCall(MatMultAdd(jac->B, ilinkD->x, ilinkA->x, ilinkA->x)); /* q = q + nu*B*b */
1303   } else {
1304     /* Situation when no augmented Lagrangian is used. Then we set inner  */
1305     /* matrix N = I in [Ar13], and thus nu = 1.                           */
1306     nu = 1;
1307   }
1308 
1309   /* Transform rhs from [q,tilde{b}] to [0,b] */
1310   PetscCall(PetscLogEventBegin(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
1311   PetscCall(KSPSolve(ksp, ilinkA->x, ilinkA->y));
1312   PetscCall(KSPCheckSolve(ksp, pc, ilinkA->y));
1313   PetscCall(PetscLogEventEnd(ilinkA->event, ksp, ilinkA->x, ilinkA->y, NULL));
1314   PetscCall(MatMultHermitianTranspose(jac->B, ilinkA->y, work1));
1315   PetscCall(VecAXPBY(work1, 1.0 / nu, -1.0, ilinkD->x)); /* c = b - B'*x        */
1316 
1317   /* First step of algorithm */
1318   PetscCall(VecNorm(work1, NORM_2, &beta)); /* beta = sqrt(nu*c'*c)*/
1319   KSPCheckDot(ksp, beta);
1320   beta = PetscSqrtReal(nu) * beta;
1321   PetscCall(VecAXPBY(v, nu / beta, 0.0, work1)); /* v = nu/beta *c      */
1322   PetscCall(MatMult(jac->B, v, work2));          /* u = H^{-1}*B*v      */
1323   PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
1324   PetscCall(KSPSolve(ksp, work2, u));
1325   PetscCall(KSPCheckSolve(ksp, pc, u));
1326   PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
1327   PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u      */
1328   PetscCall(VecDot(Hu, u, &alpha));
1329   KSPCheckDot(ksp, alpha);
1330   PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1331   alpha = PetscSqrtReal(PetscAbsScalar(alpha));
1332   PetscCall(VecScale(u, 1.0 / alpha));
1333   PetscCall(VecAXPBY(d, 1.0 / alpha, 0.0, v)); /* v = nu/beta *c      */
1334 
1335   z       = beta / alpha;
1336   vecz[1] = z;
1337 
1338   /* Computation of first iterate x(1) and p(1) */
1339   PetscCall(VecAXPY(ilinkA->y, z, u));
1340   PetscCall(VecCopy(d, ilinkD->y));
1341   PetscCall(VecScale(ilinkD->y, -z));
1342 
1343   iterGKB = 1;
1344   lowbnd  = 2 * jac->gkbtol;
1345   if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1346 
1347   while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) {
1348     iterGKB += 1;
1349     PetscCall(MatMultHermitianTranspose(jac->B, u, work1)); /* v <- nu*(B'*u-alpha/nu*v) */
1350     PetscCall(VecAXPBY(v, nu, -alpha, work1));
1351     PetscCall(VecNorm(v, NORM_2, &beta)); /* beta = sqrt(nu)*v'*v      */
1352     beta = beta / PetscSqrtReal(nu);
1353     PetscCall(VecScale(v, 1.0 / beta));
1354     PetscCall(MatMult(jac->B, v, work2)); /* u <- H^{-1}*(B*v-beta*H*u) */
1355     PetscCall(MatMult(jac->H, u, Hu));
1356     PetscCall(VecAXPY(work2, -beta, Hu));
1357     PetscCall(PetscLogEventBegin(ilinkA->event, ksp, work2, u, NULL));
1358     PetscCall(KSPSolve(ksp, work2, u));
1359     PetscCall(KSPCheckSolve(ksp, pc, u));
1360     PetscCall(PetscLogEventEnd(ilinkA->event, ksp, work2, u, NULL));
1361     PetscCall(MatMult(jac->H, u, Hu)); /* alpha = u'*H*u            */
1362     PetscCall(VecDot(Hu, u, &alpha));
1363     KSPCheckDot(ksp, alpha);
1364     PetscCheck(PetscRealPart(alpha) > 0.0, PETSC_COMM_SELF, PETSC_ERR_NOT_CONVERGED, "GKB preconditioner diverged, H is not positive definite");
1365     alpha = PetscSqrtReal(PetscAbsScalar(alpha));
1366     PetscCall(VecScale(u, 1.0 / alpha));
1367 
1368     z       = -beta / alpha * z; /* z <- beta/alpha*z     */
1369     vecz[0] = z;
1370 
1371     /* Computation of new iterate x(i+1) and p(i+1) */
1372     PetscCall(VecAXPBY(d, 1.0 / alpha, -beta / alpha, v)); /* d = (v-beta*d)/alpha */
1373     PetscCall(VecAXPY(ilinkA->y, z, u));                   /* r = r + z*u          */
1374     PetscCall(VecAXPY(ilinkD->y, -z, d));                  /* p = p - z*d          */
1375     PetscCall(MatMult(jac->H, ilinkA->y, Hu));             /* ||u||_H = u'*H*u     */
1376     PetscCall(VecDot(Hu, ilinkA->y, &nrmz2));
1377 
1378     /* Compute Lower Bound estimate */
1379     if (iterGKB > jac->gkbdelay) {
1380       lowbnd = 0.0;
1381       for (j = 0; j < jac->gkbdelay; j++) lowbnd += PetscAbsScalar(vecz[j] * vecz[j]);
1382       lowbnd = PetscSqrtReal(lowbnd / PetscAbsScalar(nrmz2));
1383     }
1384 
1385     for (j = 0; j < jac->gkbdelay - 1; j++) vecz[jac->gkbdelay - j - 1] = vecz[jac->gkbdelay - j - 2];
1386     if (jac->gkbmonitor) PetscCall(PetscViewerASCIIPrintf(jac->gkbviewer, "%3" PetscInt_FMT " GKB Lower bound estimate %14.12e\n", iterGKB, (double)lowbnd));
1387   }
1388 
1389   PetscCall(VecScatterBegin(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1390   PetscCall(VecScatterEnd(ilinkA->sctx, ilinkA->y, y, INSERT_VALUES, SCATTER_REVERSE));
1391   PetscCall(VecScatterBegin(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1392   PetscCall(VecScatterEnd(ilinkD->sctx, ilinkD->y, y, INSERT_VALUES, SCATTER_REVERSE));
1393 
1394   PetscFunctionReturn(0);
1395 }
1396 
1397 #define FieldSplitSplitSolveAddTranspose(ilink, xx, yy) \
1398   (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) || \
1399    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) || \
1400    VecScatterEnd(ilink->sctx, ilink->x, yy, ADD_VALUES, SCATTER_REVERSE))
1401 
1402 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc, Vec x, Vec y) {
1403   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1404   PC_FieldSplitLink ilink = jac->head;
1405   PetscInt          bs;
1406 
1407   PetscFunctionBegin;
1408   if (jac->type == PC_COMPOSITE_ADDITIVE) {
1409     if (jac->defaultsplit) {
1410       PetscCall(VecGetBlockSize(x, &bs));
1411       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);
1412       PetscCall(VecGetBlockSize(y, &bs));
1413       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);
1414       PetscCall(VecStrideGatherAll(x, jac->x, INSERT_VALUES));
1415       while (ilink) {
1416         PetscCall(PetscLogEventBegin(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1417         PetscCall(KSPSolveTranspose(ilink->ksp, ilink->x, ilink->y));
1418         PetscCall(KSPCheckSolve(ilink->ksp, pc, ilink->y));
1419         PetscCall(PetscLogEventEnd(ilink->event, ilink->ksp, ilink->x, ilink->y, NULL));
1420         ilink = ilink->next;
1421       }
1422       PetscCall(VecStrideScatterAll(jac->y, y, INSERT_VALUES));
1423     } else {
1424       PetscCall(VecSet(y, 0.0));
1425       while (ilink) {
1426         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
1427         ilink = ilink->next;
1428       }
1429     }
1430   } else {
1431     if (!jac->w1) {
1432       PetscCall(VecDuplicate(x, &jac->w1));
1433       PetscCall(VecDuplicate(x, &jac->w2));
1434     }
1435     PetscCall(VecSet(y, 0.0));
1436     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
1437       PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
1438       while (ilink->next) {
1439         ilink = ilink->next;
1440         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
1441         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
1442         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
1443       }
1444       while (ilink->previous) {
1445         ilink = ilink->previous;
1446         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
1447         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
1448         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
1449       }
1450     } else {
1451       while (ilink->next) { /* get to last entry in linked list */
1452         ilink = ilink->next;
1453       }
1454       PetscCall(FieldSplitSplitSolveAddTranspose(ilink, x, y));
1455       while (ilink->previous) {
1456         ilink = ilink->previous;
1457         PetscCall(MatMultTranspose(pc->mat, y, jac->w1));
1458         PetscCall(VecWAXPY(jac->w2, -1.0, jac->w1, x));
1459         PetscCall(FieldSplitSplitSolveAddTranspose(ilink, jac->w2, y));
1460       }
1461     }
1462   }
1463   PetscFunctionReturn(0);
1464 }
1465 
1466 static PetscErrorCode PCReset_FieldSplit(PC pc) {
1467   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1468   PC_FieldSplitLink ilink = jac->head, next;
1469 
1470   PetscFunctionBegin;
1471   while (ilink) {
1472     PetscCall(KSPDestroy(&ilink->ksp));
1473     PetscCall(VecDestroy(&ilink->x));
1474     PetscCall(VecDestroy(&ilink->y));
1475     PetscCall(VecDestroy(&ilink->z));
1476     PetscCall(VecScatterDestroy(&ilink->sctx));
1477     PetscCall(ISDestroy(&ilink->is));
1478     PetscCall(ISDestroy(&ilink->is_col));
1479     PetscCall(PetscFree(ilink->splitname));
1480     PetscCall(PetscFree(ilink->fields));
1481     PetscCall(PetscFree(ilink->fields_col));
1482     next = ilink->next;
1483     PetscCall(PetscFree(ilink));
1484     ilink = next;
1485   }
1486   jac->head = NULL;
1487   PetscCall(PetscFree2(jac->x, jac->y));
1488   if (jac->mat && jac->mat != jac->pmat) {
1489     PetscCall(MatDestroyMatrices(jac->nsplits, &jac->mat));
1490   } else if (jac->mat) {
1491     jac->mat = NULL;
1492   }
1493   if (jac->pmat) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->pmat));
1494   if (jac->Afield) PetscCall(MatDestroyMatrices(jac->nsplits, &jac->Afield));
1495   jac->nsplits = 0;
1496   PetscCall(VecDestroy(&jac->w1));
1497   PetscCall(VecDestroy(&jac->w2));
1498   PetscCall(MatDestroy(&jac->schur));
1499   PetscCall(MatDestroy(&jac->schurp));
1500   PetscCall(MatDestroy(&jac->schur_user));
1501   PetscCall(KSPDestroy(&jac->kspschur));
1502   PetscCall(KSPDestroy(&jac->kspupper));
1503   PetscCall(MatDestroy(&jac->B));
1504   PetscCall(MatDestroy(&jac->C));
1505   PetscCall(MatDestroy(&jac->H));
1506   PetscCall(VecDestroy(&jac->u));
1507   PetscCall(VecDestroy(&jac->v));
1508   PetscCall(VecDestroy(&jac->Hu));
1509   PetscCall(VecDestroy(&jac->d));
1510   PetscCall(PetscFree(jac->vecz));
1511   PetscCall(PetscViewerDestroy(&jac->gkbviewer));
1512   jac->isrestrict = PETSC_FALSE;
1513   PetscFunctionReturn(0);
1514 }
1515 
1516 static PetscErrorCode PCDestroy_FieldSplit(PC pc) {
1517   PetscFunctionBegin;
1518   PetscCall(PCReset_FieldSplit(pc));
1519   PetscCall(PetscFree(pc->data));
1520   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", NULL));
1521   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", NULL));
1522   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", NULL));
1523   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", NULL));
1524   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", NULL));
1525   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", NULL));
1526   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", NULL));
1527   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
1528 
1529   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
1530   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
1531   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
1532   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
1533   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
1534   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
1535   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
1536   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
1537   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
1538   PetscFunctionReturn(0);
1539 }
1540 
1541 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc, PetscOptionItems *PetscOptionsObject) {
1542   PetscInt        bs;
1543   PetscBool       flg;
1544   PC_FieldSplit  *jac = (PC_FieldSplit *)pc->data;
1545   PCCompositeType ctype;
1546 
1547   PetscFunctionBegin;
1548   PetscOptionsHeadBegin(PetscOptionsObject, "FieldSplit options");
1549   PetscCall(PetscOptionsBool("-pc_fieldsplit_dm_splits", "Whether to use DMCreateFieldDecomposition() for splits", "PCFieldSplitSetDMSplits", jac->dm_splits, &jac->dm_splits, NULL));
1550   PetscCall(PetscOptionsInt("-pc_fieldsplit_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", jac->bs, &bs, &flg));
1551   if (flg) PetscCall(PCFieldSplitSetBlockSize(pc, bs));
1552   jac->diag_use_amat = pc->useAmat;
1553   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));
1554   jac->offdiag_use_amat = pc->useAmat;
1555   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));
1556   PetscCall(PetscOptionsBool("-pc_fieldsplit_detect_saddle_point", "Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint", jac->detect, &jac->detect, NULL));
1557   PetscCall(PCFieldSplitSetDetectSaddlePoint(pc, jac->detect)); /* Sets split type and Schur PC type */
1558   PetscCall(PetscOptionsEnum("-pc_fieldsplit_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)jac->type, (PetscEnum *)&ctype, &flg));
1559   if (flg) PetscCall(PCFieldSplitSetType(pc, ctype));
1560   /* Only setup fields once */
1561   if ((jac->bs > 0) && (jac->nsplits == 0)) {
1562     /* only allow user to set fields from command line if bs is already known.
1563        otherwise user can set them in PCFieldSplitSetDefaults() */
1564     PetscCall(PCFieldSplitSetRuntimeSplits_Private(pc));
1565     if (jac->splitdefined) PetscCall(PetscInfo(pc, "Splits defined using the options database\n"));
1566   }
1567   if (jac->type == PC_COMPOSITE_SCHUR) {
1568     PetscCall(PetscOptionsGetEnum(((PetscObject)pc)->options, ((PetscObject)pc)->prefix, "-pc_fieldsplit_schur_factorization_type", PCFieldSplitSchurFactTypes, (PetscEnum *)&jac->schurfactorization, &flg));
1569     if (flg) PetscCall(PetscInfo(pc, "Deprecated use of -pc_fieldsplit_schur_factorization_type\n"));
1570     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));
1571     PetscCall(PetscOptionsEnum("-pc_fieldsplit_schur_precondition", "How to build preconditioner for Schur complement", "PCFieldSplitSetSchurPre", PCFieldSplitSchurPreTypes, (PetscEnum)jac->schurpre, (PetscEnum *)&jac->schurpre, NULL));
1572     PetscCall(PetscOptionsScalar("-pc_fieldsplit_schur_scale", "Scale Schur complement", "PCFieldSplitSetSchurScale", jac->schurscale, &jac->schurscale, NULL));
1573   } else if (jac->type == PC_COMPOSITE_GKB) {
1574     PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_tol", "The tolerance for the lower bound stopping criterion", "PCFieldSplitGKBTol", jac->gkbtol, &jac->gkbtol, NULL));
1575     PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_delay", "The delay value for lower bound criterion", "PCFieldSplitGKBDelay", jac->gkbdelay, &jac->gkbdelay, NULL));
1576     PetscCall(PetscOptionsReal("-pc_fieldsplit_gkb_nu", "Parameter in augmented Lagrangian approach", "PCFieldSplitGKBNu", jac->gkbnu, &jac->gkbnu, NULL));
1577     PetscCheck(jac->gkbnu >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "nu cannot be less than 0: value %g", (double)jac->gkbnu);
1578     PetscCall(PetscOptionsInt("-pc_fieldsplit_gkb_maxit", "Maximum allowed number of iterations", "PCFieldSplitGKBMaxit", jac->gkbmaxit, &jac->gkbmaxit, NULL));
1579     PetscCall(PetscOptionsBool("-pc_fieldsplit_gkb_monitor", "Prints number of GKB iterations and error", "PCFieldSplitGKB", jac->gkbmonitor, &jac->gkbmonitor, NULL));
1580   }
1581   /*
1582     In the initial call to this routine the sub-solver data structures do not exist so we cannot call KSPSetFromOptions() on them yet.
1583     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
1584     is called on the outer solver in case changes were made in the options database
1585 
1586     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()
1587     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.
1588     Without this extra check test p2p1fetidp_olof_full and others fail with incorrect matrix types.
1589 
1590     There could be a negative side effect of calling the KSPSetFromOptions() below.
1591 
1592     If one captured the PetscObjectState of the options database one could skip these calls if the database has not changed from the previous call
1593   */
1594   if (jac->issetup) {
1595     PC_FieldSplitLink ilink = jac->head;
1596     if (jac->type == PC_COMPOSITE_SCHUR) {
1597       if (jac->kspupper && jac->kspupper->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspupper));
1598       if (jac->kspschur && jac->kspschur->totalits > 0) PetscCall(KSPSetFromOptions(jac->kspschur));
1599     }
1600     while (ilink) {
1601       if (ilink->ksp->totalits > 0) PetscCall(KSPSetFromOptions(ilink->ksp));
1602       ilink = ilink->next;
1603     }
1604   }
1605   PetscOptionsHeadEnd();
1606   PetscFunctionReturn(0);
1607 }
1608 
1609 /*------------------------------------------------------------------------------------*/
1610 
1611 static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col) {
1612   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
1613   PC_FieldSplitLink ilink, next = jac->head;
1614   char              prefix[128];
1615   PetscInt          i;
1616 
1617   PetscFunctionBegin;
1618   if (jac->splitdefined) {
1619     PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
1620     PetscFunctionReturn(0);
1621   }
1622   for (i = 0; i < n; i++) {
1623     PetscCheck(fields[i] < jac->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", fields[i], jac->bs);
1624     PetscCheck(fields[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", fields[i]);
1625   }
1626   PetscCall(PetscNew(&ilink));
1627   if (splitname) {
1628     PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
1629   } else {
1630     PetscCall(PetscMalloc1(3, &ilink->splitname));
1631     PetscCall(PetscSNPrintf(ilink->splitname, 2, "%" PetscInt_FMT, jac->nsplits));
1632   }
1633   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + jac->nsplits : KSP_Solve_FS_0 + 4; /* Any split great than 4 gets logged in the 4th split */
1634   PetscCall(PetscMalloc1(n, &ilink->fields));
1635   PetscCall(PetscArraycpy(ilink->fields, fields, n));
1636   PetscCall(PetscMalloc1(n, &ilink->fields_col));
1637   PetscCall(PetscArraycpy(ilink->fields_col, fields_col, n));
1638 
1639   ilink->nfields = n;
1640   ilink->next    = NULL;
1641   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
1642   PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
1643   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
1644   PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
1645   PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)ilink->ksp));
1646 
1647   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
1648   PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
1649 
1650   if (!next) {
1651     jac->head       = ilink;
1652     ilink->previous = NULL;
1653   } else {
1654     while (next->next) next = next->next;
1655     next->next      = ilink;
1656     ilink->previous = next;
1657   }
1658   jac->nsplits++;
1659   PetscFunctionReturn(0);
1660 }
1661 
1662 static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp) {
1663   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1664 
1665   PetscFunctionBegin;
1666   *subksp = NULL;
1667   if (n) *n = 0;
1668   if (jac->type == PC_COMPOSITE_SCHUR) {
1669     PetscInt nn;
1670 
1671     PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()");
1672     PetscCheck(jac->nsplits == 2, PetscObjectComm((PetscObject)pc), PETSC_ERR_PLIB, "Unexpected number of splits %" PetscInt_FMT " != 2", jac->nsplits);
1673     nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0);
1674     PetscCall(PetscMalloc1(nn, subksp));
1675     (*subksp)[0] = jac->head->ksp;
1676     (*subksp)[1] = jac->kspschur;
1677     if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper;
1678     if (n) *n = nn;
1679   }
1680   PetscFunctionReturn(0);
1681 }
1682 
1683 static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc, PetscInt *n, KSP **subksp) {
1684   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1685 
1686   PetscFunctionBegin;
1687   PetscCheck(jac->schur, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONGSTATE, "Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()");
1688   PetscCall(PetscMalloc1(jac->nsplits, subksp));
1689   PetscCall(MatSchurComplementGetKSP(jac->schur, *subksp));
1690 
1691   (*subksp)[1] = jac->kspschur;
1692   if (n) *n = jac->nsplits;
1693   PetscFunctionReturn(0);
1694 }
1695 
1696 static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc, PetscInt *n, KSP **subksp) {
1697   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1698   PetscInt          cnt   = 0;
1699   PC_FieldSplitLink ilink = jac->head;
1700 
1701   PetscFunctionBegin;
1702   PetscCall(PetscMalloc1(jac->nsplits, subksp));
1703   while (ilink) {
1704     (*subksp)[cnt++] = ilink->ksp;
1705     ilink            = ilink->next;
1706   }
1707   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);
1708   if (n) *n = jac->nsplits;
1709   PetscFunctionReturn(0);
1710 }
1711 
1712 /*@C
1713     PCFieldSplitRestrictIS - Restricts the fieldsplit ISs to be within a given IS.
1714 
1715     Input Parameters:
1716 +   pc  - the preconditioner context
1717 -   is - the index set that defines the indices to which the fieldsplit is to be restricted
1718 
1719     Level: advanced
1720 
1721 @*/
1722 PetscErrorCode PCFieldSplitRestrictIS(PC pc, IS isy) {
1723   PetscFunctionBegin;
1724   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1725   PetscValidHeaderSpecific(isy, IS_CLASSID, 2);
1726   PetscTryMethod(pc, "PCFieldSplitRestrictIS_C", (PC, IS), (pc, isy));
1727   PetscFunctionReturn(0);
1728 }
1729 
1730 static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy) {
1731   PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
1732   PC_FieldSplitLink ilink = jac->head, next;
1733   PetscInt          localsize, size, sizez, i;
1734   const PetscInt   *ind, *indz;
1735   PetscInt         *indc, *indcz;
1736   PetscBool         flg;
1737 
1738   PetscFunctionBegin;
1739   PetscCall(ISGetLocalSize(isy, &localsize));
1740   PetscCallMPI(MPI_Scan(&localsize, &size, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)isy)));
1741   size -= localsize;
1742   while (ilink) {
1743     IS isrl, isr;
1744     PC subpc;
1745     PetscCall(ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl));
1746     PetscCall(ISGetLocalSize(isrl, &localsize));
1747     PetscCall(PetscMalloc1(localsize, &indc));
1748     PetscCall(ISGetIndices(isrl, &ind));
1749     PetscCall(PetscArraycpy(indc, ind, localsize));
1750     PetscCall(ISRestoreIndices(isrl, &ind));
1751     PetscCall(ISDestroy(&isrl));
1752     for (i = 0; i < localsize; i++) *(indc + i) += size;
1753     PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)isy), localsize, indc, PETSC_OWN_POINTER, &isr));
1754     PetscCall(PetscObjectReference((PetscObject)isr));
1755     PetscCall(ISDestroy(&ilink->is));
1756     ilink->is = isr;
1757     PetscCall(PetscObjectReference((PetscObject)isr));
1758     PetscCall(ISDestroy(&ilink->is_col));
1759     ilink->is_col = isr;
1760     PetscCall(ISDestroy(&isr));
1761     PetscCall(KSPGetPC(ilink->ksp, &subpc));
1762     PetscCall(PetscObjectTypeCompare((PetscObject)subpc, PCFIELDSPLIT, &flg));
1763     if (flg) {
1764       IS       iszl, isz;
1765       MPI_Comm comm;
1766       PetscCall(ISGetLocalSize(ilink->is, &localsize));
1767       comm = PetscObjectComm((PetscObject)ilink->is);
1768       PetscCall(ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl));
1769       PetscCallMPI(MPI_Scan(&localsize, &sizez, 1, MPIU_INT, MPI_SUM, comm));
1770       sizez -= localsize;
1771       PetscCall(ISGetLocalSize(iszl, &localsize));
1772       PetscCall(PetscMalloc1(localsize, &indcz));
1773       PetscCall(ISGetIndices(iszl, &indz));
1774       PetscCall(PetscArraycpy(indcz, indz, localsize));
1775       PetscCall(ISRestoreIndices(iszl, &indz));
1776       PetscCall(ISDestroy(&iszl));
1777       for (i = 0; i < localsize; i++) *(indcz + i) += sizez;
1778       PetscCall(ISCreateGeneral(comm, localsize, indcz, PETSC_OWN_POINTER, &isz));
1779       PetscCall(PCFieldSplitRestrictIS(subpc, isz));
1780       PetscCall(ISDestroy(&isz));
1781     }
1782     next  = ilink->next;
1783     ilink = next;
1784   }
1785   jac->isrestrict = PETSC_TRUE;
1786   PetscFunctionReturn(0);
1787 }
1788 
1789 static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc, const char splitname[], IS is) {
1790   PC_FieldSplit    *jac = (PC_FieldSplit *)pc->data;
1791   PC_FieldSplitLink ilink, next = jac->head;
1792   char              prefix[128];
1793 
1794   PetscFunctionBegin;
1795   if (jac->splitdefined) {
1796     PetscCall(PetscInfo(pc, "Ignoring new split \"%s\" because the splits have already been defined\n", splitname));
1797     PetscFunctionReturn(0);
1798   }
1799   PetscCall(PetscNew(&ilink));
1800   if (splitname) {
1801     PetscCall(PetscStrallocpy(splitname, &ilink->splitname));
1802   } else {
1803     PetscCall(PetscMalloc1(8, &ilink->splitname));
1804     PetscCall(PetscSNPrintf(ilink->splitname, 7, "%" PetscInt_FMT, jac->nsplits));
1805   }
1806   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + jac->nsplits : KSP_Solve_FS_0 + 4; /* Any split great than 4 gets logged in the 4th split */
1807   PetscCall(PetscObjectReference((PetscObject)is));
1808   PetscCall(ISDestroy(&ilink->is));
1809   ilink->is = is;
1810   PetscCall(PetscObjectReference((PetscObject)is));
1811   PetscCall(ISDestroy(&ilink->is_col));
1812   ilink->is_col = is;
1813   ilink->next   = NULL;
1814   PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc), &ilink->ksp));
1815   PetscCall(KSPSetErrorIfNotConverged(ilink->ksp, pc->erroriffailure));
1816   PetscCall(PetscObjectIncrementTabLevel((PetscObject)ilink->ksp, (PetscObject)pc, 1));
1817   PetscCall(KSPSetType(ilink->ksp, KSPPREONLY));
1818   PetscCall(PetscLogObjectParent((PetscObject)pc, (PetscObject)ilink->ksp));
1819 
1820   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname));
1821   PetscCall(KSPSetOptionsPrefix(ilink->ksp, prefix));
1822 
1823   if (!next) {
1824     jac->head       = ilink;
1825     ilink->previous = NULL;
1826   } else {
1827     while (next->next) next = next->next;
1828     next->next      = ilink;
1829     ilink->previous = next;
1830   }
1831   jac->nsplits++;
1832   PetscFunctionReturn(0);
1833 }
1834 
1835 /*@C
1836     PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
1837 
1838     Logically Collective on PC
1839 
1840     Input Parameters:
1841 +   pc  - the preconditioner context
1842 .   splitname - name of this split, if NULL the number of the split is used
1843 .   n - the number of fields in this split
1844 -   fields - the fields in this split
1845 
1846     Level: intermediate
1847 
1848     Notes:
1849     Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
1850 
1851      The PCFieldSplitSetFields() is for defining fields as strided blocks. For example, if the block
1852      size is three then one can define a field as 0, or 1 or 2 or 0,1 or 0,2 or 1,2 which mean
1853      0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
1854      where the numbered entries indicate what is in the field.
1855 
1856      This function is called once per split (it creates a new split each time).  Solve options
1857      for this split will be available under the prefix -fieldsplit_SPLITNAME_.
1858 
1859      Developer Note: This routine does not actually create the IS representing the split, that is delayed
1860      until PCSetUp_FieldSplit(), because information about the vector/matrix layouts may not be
1861      available when this routine is called.
1862 
1863 .seealso: `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`, `PCFieldSplitSetIS()`
1864 
1865 @*/
1866 PetscErrorCode PCFieldSplitSetFields(PC pc, const char splitname[], PetscInt n, const PetscInt *fields, const PetscInt *fields_col) {
1867   PetscFunctionBegin;
1868   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1869   PetscValidCharPointer(splitname, 2);
1870   PetscCheck(n >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, splitname);
1871   PetscValidIntPointer(fields, 4);
1872   PetscTryMethod(pc, "PCFieldSplitSetFields_C", (PC, const char[], PetscInt, const PetscInt *, const PetscInt *), (pc, splitname, n, fields, fields_col));
1873   PetscFunctionReturn(0);
1874 }
1875 
1876 /*@
1877     PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat)
1878 
1879     Logically Collective on PC
1880 
1881     Input Parameters:
1882 +   pc  - the preconditioner object
1883 -   flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
1884 
1885     Options Database:
1886 .   -pc_fieldsplit_diag_use_amat - use the Amat to provide the diagonal blocks
1887 
1888     Level: intermediate
1889 
1890 .seealso: `PCFieldSplitGetDiagUseAmat()`, `PCFieldSplitSetOffDiagUseAmat()`, `PCFIELDSPLIT`
1891 
1892 @*/
1893 PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc, PetscBool flg) {
1894   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1895   PetscBool      isfs;
1896 
1897   PetscFunctionBegin;
1898   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1899   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
1900   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
1901   jac->diag_use_amat = flg;
1902   PetscFunctionReturn(0);
1903 }
1904 
1905 /*@
1906     PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat)
1907 
1908     Logically Collective on PC
1909 
1910     Input Parameters:
1911 .   pc  - the preconditioner object
1912 
1913     Output Parameters:
1914 .   flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from
1915 
1916     Level: intermediate
1917 
1918 .seealso: `PCFieldSplitSetDiagUseAmat()`, `PCFieldSplitGetOffDiagUseAmat()`, `PCFIELDSPLIT`
1919 
1920 @*/
1921 PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc, PetscBool *flg) {
1922   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1923   PetscBool      isfs;
1924 
1925   PetscFunctionBegin;
1926   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1927   PetscValidBoolPointer(flg, 2);
1928   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
1929   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
1930   *flg = jac->diag_use_amat;
1931   PetscFunctionReturn(0);
1932 }
1933 
1934 /*@
1935     PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat)
1936 
1937     Logically Collective on PC
1938 
1939     Input Parameters:
1940 +   pc  - the preconditioner object
1941 -   flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
1942 
1943     Options Database:
1944 .     -pc_fieldsplit_off_diag_use_amat <bool> - use the Amat to extract the off-diagonal blocks
1945 
1946     Level: intermediate
1947 
1948 .seealso: `PCFieldSplitGetOffDiagUseAmat()`, `PCFieldSplitSetDiagUseAmat()`, `PCFIELDSPLIT`
1949 
1950 @*/
1951 PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc, PetscBool flg) {
1952   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1953   PetscBool      isfs;
1954 
1955   PetscFunctionBegin;
1956   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1957   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
1958   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
1959   jac->offdiag_use_amat = flg;
1960   PetscFunctionReturn(0);
1961 }
1962 
1963 /*@
1964     PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat)
1965 
1966     Logically Collective on PC
1967 
1968     Input Parameters:
1969 .   pc  - the preconditioner object
1970 
1971     Output Parameters:
1972 .   flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from
1973 
1974     Level: intermediate
1975 
1976 .seealso: `PCFieldSplitSetOffDiagUseAmat()`, `PCFieldSplitGetDiagUseAmat()`, `PCFIELDSPLIT`
1977 
1978 @*/
1979 PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc, PetscBool *flg) {
1980   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
1981   PetscBool      isfs;
1982 
1983   PetscFunctionBegin;
1984   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
1985   PetscValidBoolPointer(flg, 2);
1986   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
1987   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PC not of type %s", PCFIELDSPLIT);
1988   *flg = jac->offdiag_use_amat;
1989   PetscFunctionReturn(0);
1990 }
1991 
1992 /*@C
1993     PCFieldSplitSetIS - Sets the exact elements for field
1994 
1995     Logically Collective on PC
1996 
1997     Input Parameters:
1998 +   pc  - the preconditioner context
1999 .   splitname - name of this split, if NULL the number of the split is used
2000 -   is - the index set that defines the vector elements in this field
2001 
2002     Notes:
2003     Use PCFieldSplitSetFields(), for fields defined by strided types.
2004 
2005     This function is called once per split (it creates a new split each time).  Solve options
2006     for this split will be available under the prefix -fieldsplit_SPLITNAME_.
2007 
2008     Level: intermediate
2009 
2010 .seealso: `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetBlockSize()`
2011 
2012 @*/
2013 PetscErrorCode PCFieldSplitSetIS(PC pc, const char splitname[], IS is) {
2014   PetscFunctionBegin;
2015   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2016   if (splitname) PetscValidCharPointer(splitname, 2);
2017   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
2018   PetscTryMethod(pc, "PCFieldSplitSetIS_C", (PC, const char[], IS), (pc, splitname, is));
2019   PetscFunctionReturn(0);
2020 }
2021 
2022 /*@C
2023     PCFieldSplitGetIS - Retrieves the elements for a field as an IS
2024 
2025     Logically Collective on PC
2026 
2027     Input Parameters:
2028 +   pc  - the preconditioner context
2029 -   splitname - name of this split
2030 
2031     Output Parameter:
2032 -   is - the index set that defines the vector elements in this field, or NULL if the field is not found
2033 
2034     Level: intermediate
2035 
2036 .seealso: `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetIS()`
2037 
2038 @*/
2039 PetscErrorCode PCFieldSplitGetIS(PC pc, const char splitname[], IS *is) {
2040   PetscFunctionBegin;
2041   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2042   PetscValidCharPointer(splitname, 2);
2043   PetscValidPointer(is, 3);
2044   {
2045     PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
2046     PC_FieldSplitLink ilink = jac->head;
2047     PetscBool         found;
2048 
2049     *is = NULL;
2050     while (ilink) {
2051       PetscCall(PetscStrcmp(ilink->splitname, splitname, &found));
2052       if (found) {
2053         *is = ilink->is;
2054         break;
2055       }
2056       ilink = ilink->next;
2057     }
2058   }
2059   PetscFunctionReturn(0);
2060 }
2061 
2062 /*@C
2063     PCFieldSplitGetISByIndex - Retrieves the elements for a given index field as an IS
2064 
2065     Logically Collective on PC
2066 
2067     Input Parameters:
2068 +   pc  - the preconditioner context
2069 -   index - index of this split
2070 
2071     Output Parameter:
2072 -   is - the index set that defines the vector elements in this field
2073 
2074     Level: intermediate
2075 
2076 .seealso: `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitGetIS()`, `PCFieldSplitSetIS()`
2077 
2078 @*/
2079 PetscErrorCode PCFieldSplitGetISByIndex(PC pc, PetscInt index, IS *is) {
2080   PetscFunctionBegin;
2081   PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", index);
2082   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2083   PetscValidPointer(is, 3);
2084   {
2085     PC_FieldSplit    *jac   = (PC_FieldSplit *)pc->data;
2086     PC_FieldSplitLink ilink = jac->head;
2087     PetscInt          i     = 0;
2088     PetscCheck(index < jac->nsplits, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", index, jac->nsplits);
2089 
2090     while (i < index) {
2091       ilink = ilink->next;
2092       ++i;
2093     }
2094     PetscCall(PCFieldSplitGetIS(pc, ilink->splitname, is));
2095   }
2096   PetscFunctionReturn(0);
2097 }
2098 
2099 /*@
2100     PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
2101       fieldsplit preconditioner. If not set the matrix block size is used.
2102 
2103     Logically Collective on PC
2104 
2105     Input Parameters:
2106 +   pc  - the preconditioner context
2107 -   bs - the block size
2108 
2109     Level: intermediate
2110 
2111 .seealso: `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`
2112 
2113 @*/
2114 PetscErrorCode PCFieldSplitSetBlockSize(PC pc, PetscInt bs) {
2115   PetscFunctionBegin;
2116   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2117   PetscValidLogicalCollectiveInt(pc, bs, 2);
2118   PetscTryMethod(pc, "PCFieldSplitSetBlockSize_C", (PC, PetscInt), (pc, bs));
2119   PetscFunctionReturn(0);
2120 }
2121 
2122 /*@C
2123    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
2124 
2125    Collective on KSP
2126 
2127    Input Parameter:
2128 .  pc - the preconditioner context
2129 
2130    Output Parameters:
2131 +  n - the number of splits
2132 -  subksp - the array of KSP contexts
2133 
2134    Note:
2135    After PCFieldSplitGetSubKSP() the array of KSPs is to be freed by the user with PetscFree()
2136    (not the KSP just the array that contains them).
2137 
2138    You must call PCSetUp() before calling PCFieldSplitGetSubKSP().
2139 
2140    If the fieldsplit is of type PC_COMPOSITE_SCHUR, it returns the KSP object used inside the
2141    Schur complement and the KSP object used to iterate over the Schur complement.
2142    To access all the KSP objects used in PC_COMPOSITE_SCHUR, use PCFieldSplitSchurGetSubKSP().
2143 
2144    If the fieldsplit is of type PC_COMPOSITE_GKB, it returns the KSP object used to solve the
2145    inner linear system defined by the matrix H in each loop.
2146 
2147    Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs.
2148       You can call PCFieldSplitGetSubKSP(pc,n,PETSC_NULL_KSP,ierr) to determine how large the
2149       KSP array must be.
2150 
2151    Level: advanced
2152 
2153 .seealso: `PCFIELDSPLIT`
2154 @*/
2155 PetscErrorCode PCFieldSplitGetSubKSP(PC pc, PetscInt *n, KSP *subksp[]) {
2156   PetscFunctionBegin;
2157   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2158   if (n) PetscValidIntPointer(n, 2);
2159   PetscUseMethod(pc, "PCFieldSplitGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
2160   PetscFunctionReturn(0);
2161 }
2162 
2163 /*@C
2164    PCFieldSplitSchurGetSubKSP - Gets the KSP contexts used inside the Schur complement based PCFIELDSPLIT
2165 
2166    Collective on KSP
2167 
2168    Input Parameter:
2169 .  pc - the preconditioner context
2170 
2171    Output Parameters:
2172 +  n - the number of splits
2173 -  subksp - the array of KSP contexts
2174 
2175    Note:
2176    After PCFieldSplitSchurGetSubKSP() the array of KSPs is to be freed by the user with PetscFree()
2177    (not the KSP just the array that contains them).
2178 
2179    You must call PCSetUp() before calling PCFieldSplitSchurGetSubKSP().
2180 
2181    If the fieldsplit type is of type PC_COMPOSITE_SCHUR, it returns (in order)
2182    - the KSP used for the (1,1) block
2183    - the KSP used for the Schur complement (not the one used for the interior Schur solver)
2184    - the KSP used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block).
2185 
2186    It returns a null array if the fieldsplit is not of type PC_COMPOSITE_SCHUR; in this case, you should use PCFieldSplitGetSubKSP().
2187 
2188    Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs.
2189       You can call PCFieldSplitSchurGetSubKSP(pc,n,PETSC_NULL_KSP,ierr) to determine how large the
2190       KSP array must be.
2191 
2192    Level: advanced
2193 
2194 .seealso: `PCFIELDSPLIT`
2195 @*/
2196 PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc, PetscInt *n, KSP *subksp[]) {
2197   PetscFunctionBegin;
2198   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2199   if (n) PetscValidIntPointer(n, 2);
2200   PetscUseMethod(pc, "PCFieldSplitSchurGetSubKSP_C", (PC, PetscInt *, KSP **), (pc, n, subksp));
2201   PetscFunctionReturn(0);
2202 }
2203 
2204 /*@
2205     PCFieldSplitSetSchurPre -  Indicates from what operator the preconditioner is constructucted for the Schur complement.
2206       The default is the A11 matrix.
2207 
2208     Collective on PC
2209 
2210     Input Parameters:
2211 +   pc      - the preconditioner context
2212 .   ptype   - which matrix to use for preconditioning the Schur complement: PC_FIELDSPLIT_SCHUR_PRE_A11 (default), PC_FIELDSPLIT_SCHUR_PRE_SELF, PC_FIELDSPLIT_SCHUR_PRE_USER
2213               PC_FIELDSPLIT_SCHUR_PRE_SELFP, and PC_FIELDSPLIT_SCHUR_PRE_FULL
2214 -   userpre - matrix to use for preconditioning, or NULL
2215 
2216     Options Database:
2217 +    -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is a11. See notes for meaning of various arguments
2218 -    -fieldsplit_1_pc_type <pctype> - the preconditioner algorithm that is used to construct the preconditioner from the operator
2219 
2220     Notes:
2221 $    If ptype is
2222 $        a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner
2223 $        matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix
2224 $        self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix:
2225 $             The only preconditioner that currently works with this symbolic respresentation matrix object is the PCLSC
2226 $             preconditioner
2227 $        user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument
2228 $             to this function).
2229 $        selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation Sp = A11 - A10 inv(diag(A00)) A01
2230 $             This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be
2231 $             lumped before extracting the diagonal using the additional option -fieldsplit_1_mat_schur_complement_ainv_type lump
2232 $        full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation computed internally by PCFIELDSPLIT (this is expensive)
2233 $             useful mostly as a test that the Schur complement approach can work for your problem
2234 
2235      When solving a saddle point problem, where the A11 block is identically zero, using a11 as the ptype only makes sense
2236     with the additional option -fieldsplit_1_pc_type none. Usually for saddle point problems one would use a ptype of self and
2237     -fieldsplit_1_pc_type lsc which uses the least squares commutator to compute a preconditioner for the Schur complement.
2238 
2239     Level: intermediate
2240 
2241 .seealso: `PCFieldSplitGetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`,
2242           `MatSchurComplementSetAinvType()`, `PCLSC`
2243 
2244 @*/
2245 PetscErrorCode PCFieldSplitSetSchurPre(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) {
2246   PetscFunctionBegin;
2247   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2248   PetscTryMethod(pc, "PCFieldSplitSetSchurPre_C", (PC, PCFieldSplitSchurPreType, Mat), (pc, ptype, pre));
2249   PetscFunctionReturn(0);
2250 }
2251 
2252 PetscErrorCode PCFieldSplitSchurPrecondition(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) {
2253   return PCFieldSplitSetSchurPre(pc, ptype, pre);
2254 } /* Deprecated name */
2255 
2256 /*@
2257     PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be
2258     preconditioned.  See PCFieldSplitSetSchurPre() for details.
2259 
2260     Logically Collective on PC
2261 
2262     Input Parameter:
2263 .   pc      - the preconditioner context
2264 
2265     Output Parameters:
2266 +   ptype   - which matrix to use for preconditioning the Schur complement: PC_FIELDSPLIT_SCHUR_PRE_A11, PC_FIELDSPLIT_SCHUR_PRE_SELF, PC_FIELDSPLIT_PRE_USER
2267 -   userpre - matrix to use for preconditioning (with PC_FIELDSPLIT_PRE_USER), or NULL
2268 
2269     Level: intermediate
2270 
2271 .seealso: `PCFieldSplitSetSchurPre()`, `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCLSC`
2272 
2273 @*/
2274 PetscErrorCode PCFieldSplitGetSchurPre(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre) {
2275   PetscFunctionBegin;
2276   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2277   PetscUseMethod(pc, "PCFieldSplitGetSchurPre_C", (PC, PCFieldSplitSchurPreType *, Mat *), (pc, ptype, pre));
2278   PetscFunctionReturn(0);
2279 }
2280 
2281 /*@
2282     PCFieldSplitSchurGetS -  extract the MatSchurComplement object used by this PC in case it needs to be configured separately
2283 
2284     Not collective
2285 
2286     Input Parameter:
2287 .   pc      - the preconditioner context
2288 
2289     Output Parameter:
2290 .   S       - the Schur complement matrix
2291 
2292     Notes:
2293     This matrix should not be destroyed using MatDestroy(); rather, use PCFieldSplitSchurRestoreS().
2294 
2295     Level: advanced
2296 
2297 .seealso: `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurRestoreS()`
2298 
2299 @*/
2300 PetscErrorCode PCFieldSplitSchurGetS(PC pc, Mat *S) {
2301   const char    *t;
2302   PetscBool      isfs;
2303   PC_FieldSplit *jac;
2304 
2305   PetscFunctionBegin;
2306   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2307   PetscCall(PetscObjectGetType((PetscObject)pc, &t));
2308   PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
2309   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
2310   jac = (PC_FieldSplit *)pc->data;
2311   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
2312   if (S) *S = jac->schur;
2313   PetscFunctionReturn(0);
2314 }
2315 
2316 /*@
2317     PCFieldSplitSchurRestoreS -  restores the MatSchurComplement object used by this PC
2318 
2319     Not collective
2320 
2321     Input Parameters:
2322 +   pc      - the preconditioner context
2323 -   S       - the Schur complement matrix
2324 
2325     Level: advanced
2326 
2327 .seealso: `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurPre()`, `MatSchurComplement`, `PCFieldSplitSchurGetS()`
2328 
2329 @*/
2330 PetscErrorCode PCFieldSplitSchurRestoreS(PC pc, Mat *S) {
2331   const char    *t;
2332   PetscBool      isfs;
2333   PC_FieldSplit *jac;
2334 
2335   PetscFunctionBegin;
2336   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2337   PetscCall(PetscObjectGetType((PetscObject)pc, &t));
2338   PetscCall(PetscStrcmp(t, PCFIELDSPLIT, &isfs));
2339   PetscCheck(isfs, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PC of type PCFIELDSPLIT, got %s instead", t);
2340   jac = (PC_FieldSplit *)pc->data;
2341   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Expected PCFIELDSPLIT of type SCHUR, got %d instead", jac->type);
2342   PetscCheck(S && (*S == jac->schur), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "MatSchurComplement restored is not the same as gotten");
2343   PetscFunctionReturn(0);
2344 }
2345 
2346 static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType ptype, Mat pre) {
2347   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2348 
2349   PetscFunctionBegin;
2350   jac->schurpre = ptype;
2351   if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) {
2352     PetscCall(MatDestroy(&jac->schur_user));
2353     jac->schur_user = pre;
2354     PetscCall(PetscObjectReference((PetscObject)jac->schur_user));
2355   }
2356   PetscFunctionReturn(0);
2357 }
2358 
2359 static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc, PCFieldSplitSchurPreType *ptype, Mat *pre) {
2360   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2361 
2362   PetscFunctionBegin;
2363   *ptype = jac->schurpre;
2364   *pre   = jac->schur_user;
2365   PetscFunctionReturn(0);
2366 }
2367 
2368 /*@
2369     PCFieldSplitSetSchurFactType -  sets which blocks of the approximate block factorization to retain in the preconditioner
2370 
2371     Collective on PC
2372 
2373     Input Parameters:
2374 +   pc  - the preconditioner context
2375 -   ftype - which blocks of factorization to retain, PC_FIELDSPLIT_SCHUR_FACT_FULL is default
2376 
2377     Options Database:
2378 .     -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - default is full
2379 
2380     Level: intermediate
2381 
2382     Notes:
2383     The FULL factorization is
2384 
2385 .vb
2386    (A   B)  = (1       0) (A   0) (1  Ainv*B)  = L D U
2387    (C   E)    (C*Ainv  1) (0   S) (0     1)
2388 .vb
2389     where S = E - C*Ainv*B. In practice, the full factorization is applied via block triangular solves with the grouping L*(D*U). UPPER uses D*U, LOWER uses L*D,
2390     and DIAG is the diagonal part with the sign of S flipped (because this makes the preconditioner positive definite for many formulations, thus allowing the use of KSPMINRES). Sign flipping of S can be turned off with PCFieldSplitSetSchurScale().
2391 
2392     If A and S are solved exactly
2393 .vb
2394       *) FULL factorization is a direct solver.
2395       *) 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.
2396       *) 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.
2397 .ve
2398 
2399     If the iteration count is very low, consider using KSPFGMRES or KSPGCR which can use one less preconditioner
2400     application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice.
2401 
2402     For symmetric problems in which A is positive definite and S is negative definite, DIAG can be used with KSPMINRES.
2403 
2404     Note that a flexible method like KSPFGMRES or KSPGCR 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).
2405 
2406     References:
2407 +   * - Murphy, Golub, and Wathen, A note on preconditioning indefinite linear systems, SIAM J. Sci. Comput., 21 (2000).
2408 -   * - Ipsen, A note on preconditioning nonsymmetric matrices, SIAM J. Sci. Comput., 23 (2001).
2409 
2410 .seealso: `PCFieldSplitGetSubKSP()`, `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurPreType`, `PCFieldSplitSetSchurScale()`
2411 @*/
2412 PetscErrorCode PCFieldSplitSetSchurFactType(PC pc, PCFieldSplitSchurFactType ftype) {
2413   PetscFunctionBegin;
2414   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2415   PetscTryMethod(pc, "PCFieldSplitSetSchurFactType_C", (PC, PCFieldSplitSchurFactType), (pc, ftype));
2416   PetscFunctionReturn(0);
2417 }
2418 
2419 static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc, PCFieldSplitSchurFactType ftype) {
2420   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2421 
2422   PetscFunctionBegin;
2423   jac->schurfactorization = ftype;
2424   PetscFunctionReturn(0);
2425 }
2426 
2427 /*@
2428     PCFieldSplitSetSchurScale -  Controls the sign flip of S for PC_FIELDSPLIT_SCHUR_FACT_DIAG.
2429 
2430     Collective on PC
2431 
2432     Input Parameters:
2433 +   pc    - the preconditioner context
2434 -   scale - scaling factor for the Schur complement
2435 
2436     Options Database:
2437 .     -pc_fieldsplit_schur_scale - default is -1.0
2438 
2439     Level: intermediate
2440 
2441 .seealso: `PCFIELDSPLIT`, `PCFieldSplitSetFields()`, `PCFieldSplitSchurFactType`, `PCFieldSplitSetSchurScale()`
2442 @*/
2443 PetscErrorCode PCFieldSplitSetSchurScale(PC pc, PetscScalar scale) {
2444   PetscFunctionBegin;
2445   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2446   PetscValidLogicalCollectiveScalar(pc, scale, 2);
2447   PetscTryMethod(pc, "PCFieldSplitSetSchurScale_C", (PC, PetscScalar), (pc, scale));
2448   PetscFunctionReturn(0);
2449 }
2450 
2451 static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc, PetscScalar scale) {
2452   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2453 
2454   PetscFunctionBegin;
2455   jac->schurscale = scale;
2456   PetscFunctionReturn(0);
2457 }
2458 
2459 /*@C
2460    PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
2461 
2462    Collective on KSP
2463 
2464    Input Parameter:
2465 .  pc - the preconditioner context
2466 
2467    Output Parameters:
2468 +  A00 - the (0,0) block
2469 .  A01 - the (0,1) block
2470 .  A10 - the (1,0) block
2471 -  A11 - the (1,1) block
2472 
2473    Level: advanced
2474 
2475 .seealso: `PCFIELDSPLIT`
2476 @*/
2477 PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc, Mat *A00, Mat *A01, Mat *A10, Mat *A11) {
2478   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2479 
2480   PetscFunctionBegin;
2481   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2482   PetscCheck(jac->type == PC_COMPOSITE_SCHUR, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
2483   if (A00) *A00 = jac->pmat[0];
2484   if (A01) *A01 = jac->B;
2485   if (A10) *A10 = jac->C;
2486   if (A11) *A11 = jac->pmat[1];
2487   PetscFunctionReturn(0);
2488 }
2489 
2490 /*@
2491     PCFieldSplitSetGKBTol -  Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner.
2492 
2493     Collective on PC
2494 
2495     Notes:
2496     The generalized GKB algorithm uses a lower bound estimate of the error in energy norm as stopping criterion.
2497     It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than
2498     this estimate, the stopping criterion is satisfactory in practical cases [A13].
2499 
2500 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013.
2501 
2502     Input Parameters:
2503 +   pc        - the preconditioner context
2504 -   tolerance - the solver tolerance
2505 
2506     Options Database:
2507 .     -pc_fieldsplit_gkb_tol - default is 1e-5
2508 
2509     Level: intermediate
2510 
2511 .seealso: `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBMaxit()`
2512 @*/
2513 PetscErrorCode PCFieldSplitSetGKBTol(PC pc, PetscReal tolerance) {
2514   PetscFunctionBegin;
2515   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2516   PetscValidLogicalCollectiveReal(pc, tolerance, 2);
2517   PetscTryMethod(pc, "PCFieldSplitSetGKBTol_C", (PC, PetscReal), (pc, tolerance));
2518   PetscFunctionReturn(0);
2519 }
2520 
2521 static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc, PetscReal tolerance) {
2522   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2523 
2524   PetscFunctionBegin;
2525   jac->gkbtol = tolerance;
2526   PetscFunctionReturn(0);
2527 }
2528 
2529 /*@
2530     PCFieldSplitSetGKBMaxit -  Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization
2531     preconditioner.
2532 
2533     Collective on PC
2534 
2535     Input Parameters:
2536 +   pc     - the preconditioner context
2537 -   maxit  - the maximum number of iterations
2538 
2539     Options Database:
2540 .     -pc_fieldsplit_gkb_maxit - default is 100
2541 
2542     Level: intermediate
2543 
2544 .seealso: `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBNu()`
2545 @*/
2546 PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc, PetscInt maxit) {
2547   PetscFunctionBegin;
2548   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2549   PetscValidLogicalCollectiveInt(pc, maxit, 2);
2550   PetscTryMethod(pc, "PCFieldSplitSetGKBMaxit_C", (PC, PetscInt), (pc, maxit));
2551   PetscFunctionReturn(0);
2552 }
2553 
2554 static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc, PetscInt maxit) {
2555   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2556 
2557   PetscFunctionBegin;
2558   jac->gkbmaxit = maxit;
2559   PetscFunctionReturn(0);
2560 }
2561 
2562 /*@
2563     PCFieldSplitSetGKBDelay -  Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization
2564     preconditioner.
2565 
2566     Collective on PC
2567 
2568     Notes:
2569     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
2570     is expressed as a truncated sum. The error at iteration k can only be measured at iteration (k + delay), and thus the algorithm needs
2571     at least (delay + 1) iterations to stop. For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to
2572 
2573 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013.
2574 
2575     Input Parameters:
2576 +   pc     - the preconditioner context
2577 -   delay  - the delay window in the lower bound estimate
2578 
2579     Options Database:
2580 .     -pc_fieldsplit_gkb_delay - default is 5
2581 
2582     Level: intermediate
2583 
2584 .seealso: `PCFIELDSPLIT`, `PCFieldSplitSetGKBNu()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
2585 @*/
2586 PetscErrorCode PCFieldSplitSetGKBDelay(PC pc, PetscInt delay) {
2587   PetscFunctionBegin;
2588   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2589   PetscValidLogicalCollectiveInt(pc, delay, 2);
2590   PetscTryMethod(pc, "PCFieldSplitSetGKBDelay_C", (PC, PetscInt), (pc, delay));
2591   PetscFunctionReturn(0);
2592 }
2593 
2594 static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc, PetscInt delay) {
2595   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2596 
2597   PetscFunctionBegin;
2598   jac->gkbdelay = delay;
2599   PetscFunctionReturn(0);
2600 }
2601 
2602 /*@
2603     PCFieldSplitSetGKBNu -  Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the Golub-Kahan bidiagonalization preconditioner.
2604 
2605     Collective on PC
2606 
2607     Notes:
2608     This shift is in general done to obtain better convergence properties for the outer loop of the algorithm. This is often achieved by chosing nu sufficiently big. However,
2609     if nu is chosen too big, the matrix H might be badly conditioned and the solution of the linear system Hx = b in the inner loop gets difficult. It is therefore
2610     necessary to find a good balance in between the convergence of the inner and outer loop.
2611 
2612     For nu = 0, no shift is done. In this case A00 has to be positive definite. The matrix N in [Ar13] is then chosen as identity.
2613 
2614 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013.
2615 
2616     Input Parameters:
2617 +   pc     - the preconditioner context
2618 -   nu     - the shift parameter
2619 
2620     Options Database:
2621 .     -pc_fieldsplit_gkb_nu - default is 1
2622 
2623     Level: intermediate
2624 
2625 .seealso: `PCFIELDSPLIT`, `PCFieldSplitSetGKBDelay()`, `PCFieldSplitSetGKBTol()`, `PCFieldSplitSetGKBMaxit()`
2626 @*/
2627 PetscErrorCode PCFieldSplitSetGKBNu(PC pc, PetscReal nu) {
2628   PetscFunctionBegin;
2629   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2630   PetscValidLogicalCollectiveReal(pc, nu, 2);
2631   PetscTryMethod(pc, "PCFieldSplitSetGKBNu_C", (PC, PetscReal), (pc, nu));
2632   PetscFunctionReturn(0);
2633 }
2634 
2635 static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc, PetscReal nu) {
2636   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2637 
2638   PetscFunctionBegin;
2639   jac->gkbnu = nu;
2640   PetscFunctionReturn(0);
2641 }
2642 
2643 static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc, PCCompositeType type) {
2644   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2645 
2646   PetscFunctionBegin;
2647   jac->type = type;
2648   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", NULL));
2649   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", NULL));
2650   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", NULL));
2651   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", NULL));
2652   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", NULL));
2653   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", NULL));
2654   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", NULL));
2655   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", NULL));
2656   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", NULL));
2657 
2658   if (type == PC_COMPOSITE_SCHUR) {
2659     pc->ops->apply = PCApply_FieldSplit_Schur;
2660     pc->ops->view  = PCView_FieldSplit_Schur;
2661 
2662     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit_Schur));
2663     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurPre_C", PCFieldSplitSetSchurPre_FieldSplit));
2664     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSchurPre_C", PCFieldSplitGetSchurPre_FieldSplit));
2665     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurFactType_C", PCFieldSplitSetSchurFactType_FieldSplit));
2666     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetSchurScale_C", PCFieldSplitSetSchurScale_FieldSplit));
2667   } else if (type == PC_COMPOSITE_GKB) {
2668     pc->ops->apply = PCApply_FieldSplit_GKB;
2669     pc->ops->view  = PCView_FieldSplit_GKB;
2670 
2671     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
2672     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBTol_C", PCFieldSplitSetGKBTol_FieldSplit));
2673     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBMaxit_C", PCFieldSplitSetGKBMaxit_FieldSplit));
2674     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBNu_C", PCFieldSplitSetGKBNu_FieldSplit));
2675     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetGKBDelay_C", PCFieldSplitSetGKBDelay_FieldSplit));
2676   } else {
2677     pc->ops->apply = PCApply_FieldSplit;
2678     pc->ops->view  = PCView_FieldSplit;
2679 
2680     PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
2681   }
2682   PetscFunctionReturn(0);
2683 }
2684 
2685 static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc, PetscInt bs) {
2686   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2687 
2688   PetscFunctionBegin;
2689   PetscCheck(bs >= 1, PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs);
2690   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);
2691   jac->bs = bs;
2692   PetscFunctionReturn(0);
2693 }
2694 
2695 static PetscErrorCode PCSetCoordinates_FieldSplit(PC pc, PetscInt dim, PetscInt nloc, PetscReal coords[]) {
2696   PC_FieldSplit    *jac           = (PC_FieldSplit *)pc->data;
2697   PC_FieldSplitLink ilink_current = jac->head;
2698   IS                is_owned;
2699 
2700   PetscFunctionBegin;
2701   jac->coordinates_set = PETSC_TRUE; // Internal flag
2702   PetscCall(MatGetOwnershipIS(pc->mat, &is_owned, PETSC_NULL));
2703 
2704   while (ilink_current) {
2705     // For each IS, embed it to get local coords indces
2706     IS              is_coords;
2707     PetscInt        ndofs_block;
2708     const PetscInt *block_dofs_enumeration; // Numbering of the dofs relevant to the current block
2709 
2710     // Setting drop to true for safety. It should make no difference.
2711     PetscCall(ISEmbed(ilink_current->is, is_owned, PETSC_TRUE, &is_coords));
2712     PetscCall(ISGetLocalSize(is_coords, &ndofs_block));
2713     PetscCall(ISGetIndices(is_coords, &block_dofs_enumeration));
2714 
2715     // Allocate coordinates vector and set it directly
2716     PetscCall(PetscMalloc1(ndofs_block * dim, &(ilink_current->coords)));
2717     for (PetscInt dof = 0; dof < ndofs_block; ++dof) {
2718       for (PetscInt d = 0; d < dim; ++d) (ilink_current->coords)[dim * dof + d] = coords[dim * block_dofs_enumeration[dof] + d];
2719     }
2720     ilink_current->dim   = dim;
2721     ilink_current->ndofs = ndofs_block;
2722     PetscCall(ISRestoreIndices(is_coords, &block_dofs_enumeration));
2723     PetscCall(ISDestroy(&is_coords));
2724     ilink_current = ilink_current->next;
2725   }
2726   PetscCall(ISDestroy(&is_owned));
2727   PetscFunctionReturn(0);
2728 }
2729 
2730 /*@
2731    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
2732 
2733    Collective on PC
2734 
2735    Input Parameters:
2736 +  pc - the preconditioner context
2737 -  type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
2738 
2739    Options Database Key:
2740 .  -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
2741 
2742    Level: Intermediate
2743 
2744 .seealso: `PCCompositeSetType()`
2745 
2746 @*/
2747 PetscErrorCode PCFieldSplitSetType(PC pc, PCCompositeType type) {
2748   PetscFunctionBegin;
2749   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2750   PetscTryMethod(pc, "PCFieldSplitSetType_C", (PC, PCCompositeType), (pc, type));
2751   PetscFunctionReturn(0);
2752 }
2753 
2754 /*@
2755   PCFieldSplitGetType - Gets the type of fieldsplit preconditioner.
2756 
2757   Not collective
2758 
2759   Input Parameter:
2760 . pc - the preconditioner context
2761 
2762   Output Parameter:
2763 . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
2764 
2765   Level: Intermediate
2766 
2767 .seealso: `PCCompositeSetType()`
2768 @*/
2769 PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type) {
2770   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2771 
2772   PetscFunctionBegin;
2773   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2774   PetscValidIntPointer(type, 2);
2775   *type = jac->type;
2776   PetscFunctionReturn(0);
2777 }
2778 
2779 /*@
2780    PCFieldSplitSetDMSplits - Flags whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible.
2781 
2782    Logically Collective
2783 
2784    Input Parameters:
2785 +  pc   - the preconditioner context
2786 -  flg  - boolean indicating whether to use field splits defined by the DM
2787 
2788    Options Database Key:
2789 .  -pc_fieldsplit_dm_splits <bool> - use the field splits defined by the DM
2790 
2791    Level: Intermediate
2792 
2793 .seealso: `PCFieldSplitGetDMSplits()`
2794 
2795 @*/
2796 PetscErrorCode PCFieldSplitSetDMSplits(PC pc, PetscBool flg) {
2797   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2798   PetscBool      isfs;
2799 
2800   PetscFunctionBegin;
2801   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2802   PetscValidLogicalCollectiveBool(pc, flg, 2);
2803   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
2804   if (isfs) jac->dm_splits = flg;
2805   PetscFunctionReturn(0);
2806 }
2807 
2808 /*@
2809    PCFieldSplitGetDMSplits - Returns flag indicating whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible.
2810 
2811    Logically Collective
2812 
2813    Input Parameter:
2814 .  pc   - the preconditioner context
2815 
2816    Output Parameter:
2817 .  flg  - boolean indicating whether to use field splits defined by the DM
2818 
2819    Level: Intermediate
2820 
2821 .seealso: `PCFieldSplitSetDMSplits()`
2822 
2823 @*/
2824 PetscErrorCode PCFieldSplitGetDMSplits(PC pc, PetscBool *flg) {
2825   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2826   PetscBool      isfs;
2827 
2828   PetscFunctionBegin;
2829   PetscValidHeaderSpecific(pc, PC_CLASSID, 1);
2830   PetscValidBoolPointer(flg, 2);
2831   PetscCall(PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &isfs));
2832   if (isfs) {
2833     if (flg) *flg = jac->dm_splits;
2834   }
2835   PetscFunctionReturn(0);
2836 }
2837 
2838 /*@
2839    PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether PCFieldSplit will attempt to automatically determine fields based on zero diagonal entries.
2840 
2841    Logically Collective
2842 
2843    Input Parameter:
2844 .  pc   - the preconditioner context
2845 
2846    Output Parameter:
2847 .  flg  - boolean indicating whether to detect fields or not
2848 
2849    Level: Intermediate
2850 
2851 .seealso: `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()`
2852 
2853 @*/
2854 PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc, PetscBool *flg) {
2855   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2856 
2857   PetscFunctionBegin;
2858   *flg = jac->detect;
2859   PetscFunctionReturn(0);
2860 }
2861 
2862 /*@
2863    PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether PCFieldSplit will attempt to automatically determine fields based on zero diagonal entries.
2864 
2865    Logically Collective
2866 
2867    Input Parameter:
2868 .  pc   - the preconditioner context
2869 
2870    Output Parameter:
2871 .  flg  - boolean indicating whether to detect fields or not
2872 
2873    Options Database Key:
2874 .  -pc_fieldsplit_detect_saddle_point <bool> - detect and use the saddle point
2875 
2876    Notes:
2877    Also sets the split type to PC_COMPOSITE_SCHUR (see PCFieldSplitSetType()) and the Schur preconditioner type to PC_FIELDSPLIT_SCHUR_PRE_SELF (see PCFieldSplitSetSchurPre()).
2878 
2879    Level: Intermediate
2880 
2881 .seealso: `PCFIELDSPLIT`, `PCFieldSplitSetDetectSaddlePoint()`, `PCFieldSplitSetType()`, `PCFieldSplitSetSchurPre()`
2882 
2883 @*/
2884 PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc, PetscBool flg) {
2885   PC_FieldSplit *jac = (PC_FieldSplit *)pc->data;
2886 
2887   PetscFunctionBegin;
2888   jac->detect = flg;
2889   if (jac->detect) {
2890     PetscCall(PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR));
2891     PetscCall(PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_SELF, NULL));
2892   }
2893   PetscFunctionReturn(0);
2894 }
2895 
2896 /* -------------------------------------------------------------------------------------*/
2897 /*MC
2898    PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
2899                   fields or groups of fields. See [the users manual section on "Solving Block Matrices"](sec_block_matrices) for more details.
2900 
2901      To set options on the solvers for each block append `-fieldsplit_` to all the PC
2902         options database keys. For example, `-fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1`
2903 
2904      To set the options on the solvers separate for each block call `PCFieldSplitGetSubKSP()`
2905          and set the options directly on the resulting `KSP` object
2906 
2907    Level: intermediate
2908 
2909    Options Database Keys:
2910 +   -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the `%d`'th split
2911 .   -pc_fieldsplit_default - automatically add any fields to additional splits that have not
2912                               been supplied explicitly by `-pc_fieldsplit_%d_fields`
2913 .   -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
2914 .   -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting
2915 .   -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is a11; see `PCFieldSplitSetSchurPre()`
2916 .   -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - set factorization type when using `-pc_fieldsplit_type schur`; see `PCFieldSplitSetSchurFactType()`
2917 -   -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver
2918 
2919      Options prefixes for inner solvers when using the Schur complement preconditioner are `-fieldsplit_0_` and `-fieldsplit_1_` .
2920      For all other solvers they are `-fieldsplit_%d_` for the `d`th field; use `-fieldsplit_` for all fields.
2921      The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is `-fieldsplit_0_`
2922 
2923    Notes:
2924     Use `PCFieldSplitSetFields()` to set fields defined by "strided" entries and `PCFieldSplitSetIS()`
2925      to define a field by an arbitrary collection of entries.
2926 
2927       If no fields are set the default is used. The fields are defined by entries strided by bs,
2928       beginning at 0 then 1, etc to bs-1. The block size can be set with `PCFieldSplitSetBlockSize()`,
2929       if this is not called the block size defaults to the blocksize of the second matrix passed
2930       to `KSPSetOperators()`/`PCSetOperators()`.
2931 
2932       For the Schur complement preconditioner if
2933 
2934       ```{math}
2935       J = \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{10} & A_{11} \end{array}\right]
2936       ```
2937 
2938       the preconditioner using `full` factorization is logically
2939       ```{math}
2940       \left[\begin{array}{cc} I & -\text{ksp}(A_{00}) \\ 0 & I \end{array}\right] \left[\begin{array}{cc} \text{inv}(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]
2941       ```
2942      where the action of $\text{inv}(A_{00})$ is applied using the KSP solver with prefix `-fieldsplit_0_`.  $S$ is the Schur complement
2943      ```{math}
2944      S = A_{11} - A_{10} \text{ksp}(A_{00}) A_{01}
2945      ```
2946      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` was given
2947      in providing the SECOND split or 1 if not given). For `PCFieldSplitGetSub\text{ksp}()` when field number is 0,
2948      it returns the KSP associated with `-fieldsplit_0_` while field number 1 gives `-fieldsplit_1_` KSP. By default
2949      $A_{11}$ is used to construct a preconditioner for $S$, use `PCFieldSplitSetSchurPre()` for all the possible ways to construct the preconditioner for $S$.
2950 
2951      The factorization type is set using `-pc_fieldsplit_schur_fact_type <diag, lower, upper, full>`. `full` is shown above,
2952      `diag` gives
2953       ```{math}
2954       \left[\begin{array}{cc} \text{inv}(A_{00}) & 0 \\  0 & -\text{ksp}(S) \end{array}\right]
2955       ```
2956      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
2957      can be turned off with `PCFieldSplitSetSchurScale()` or by command line `-pc_fieldsplit_schur_scale 1.0`. The `lower` factorization is the inverse of
2958       ```{math}
2959       \left[\begin{array}{cc} A_{00} & 0 \\  A_{10} & S \end{array}\right]
2960       ```
2961      where the inverses of A_{00} and S are applied using KSPs. The upper factorization is the inverse of
2962       ```{math}
2963       \left[\begin{array}{cc} A_{00} & A_{01} \\  0 & S \end{array}\right]
2964       ```
2965      where again the inverses of $A_{00}$ and $S$ are applied using `KSP`s.
2966 
2967      If only one set of indices (one `IS`) is provided with `PCFieldSplitSetIS()` then the complement of that `IS`
2968      is used automatically for a second block.
2969 
2970      The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1.
2971      Generally it should be used with the AIJ format.
2972 
2973      The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see,
2974      for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling {cite}`Wesseling2009`. Note that one can also use `PCFIELDSPLIT`
2975      inside a smoother resulting in "Distributive Smoothers".
2976 
2977      References:
2978 
2979      See "A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations" {cite}`elman2008tcp`.
2980 
2981      The Constrained Pressure Preconditioner (CPR) can be implemented using `PCCOMPOSITE` with `PCGALERKIN`. CPR first solves an $R A P$ subsystem, updates the
2982      residual on all variables (`PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)`), and then applies a simple ILU like preconditioner on all the variables.
2983 
2984      The generalized Golub-Kahan bidiagonalization preconditioner (GKB) can be applied to symmetric $2 \times 2$ block matrices of the shape
2985      ```{math}
2986      \left[\begin{array}{cc} A_{00} & A_{01} \\ A_{01}' & 0 \end{array}\right]
2987      ```
2988      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}'$.
2989      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_`.
2990 
2991      ```{bibliography}
2992      :filter: docname in docnames
2993      ```
2994 
2995 .seealso: `PCCreate()`, `PCSetType()`, `PCType`, `PC`, `PCLSC`,
2996           `PCFieldSplitGetSubKSP()`, `PCFieldSplitSchurGetSubKSP()`, `PCFieldSplitSetFields()`,
2997           `PCFieldSplitSetType()`, `PCFieldSplitSetIS()`, `PCFieldSplitSetSchurPre()`, `PCFieldSplitSetSchurFactType()`,
2998           `MatSchurComplementSetAinvType()`, `PCFieldSplitSetSchurScale()`, `PCFieldSplitSetDetectSaddlePoint()`
2999 M*/
3000 
3001 PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc) {
3002   PC_FieldSplit *jac;
3003 
3004   PetscFunctionBegin;
3005   PetscCall(PetscNewLog(pc, &jac));
3006 
3007   jac->bs                 = -1;
3008   jac->nsplits            = 0;
3009   jac->type               = PC_COMPOSITE_MULTIPLICATIVE;
3010   jac->schurpre           = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
3011   jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL;
3012   jac->schurscale         = -1.0;
3013   jac->dm_splits          = PETSC_TRUE;
3014   jac->detect             = PETSC_FALSE;
3015   jac->gkbtol             = 1e-5;
3016   jac->gkbdelay           = 5;
3017   jac->gkbnu              = 1;
3018   jac->gkbmaxit           = 100;
3019   jac->gkbmonitor         = PETSC_FALSE;
3020   jac->coordinates_set    = PETSC_FALSE;
3021 
3022   pc->data = (void *)jac;
3023 
3024   pc->ops->apply           = PCApply_FieldSplit;
3025   pc->ops->applytranspose  = PCApplyTranspose_FieldSplit;
3026   pc->ops->setup           = PCSetUp_FieldSplit;
3027   pc->ops->reset           = PCReset_FieldSplit;
3028   pc->ops->destroy         = PCDestroy_FieldSplit;
3029   pc->ops->setfromoptions  = PCSetFromOptions_FieldSplit;
3030   pc->ops->view            = PCView_FieldSplit;
3031   pc->ops->applyrichardson = NULL;
3032 
3033   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSchurGetSubKSP_C", PCFieldSplitSchurGetSubKSP_FieldSplit));
3034   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitGetSubKSP_C", PCFieldSplitGetSubKSP_FieldSplit));
3035   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetFields_C", PCFieldSplitSetFields_FieldSplit));
3036   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetIS_C", PCFieldSplitSetIS_FieldSplit));
3037   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetType_C", PCFieldSplitSetType_FieldSplit));
3038   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitSetBlockSize_C", PCFieldSplitSetBlockSize_FieldSplit));
3039   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCFieldSplitRestrictIS_C", PCFieldSplitRestrictIS_FieldSplit));
3040   PetscCall(PetscObjectComposeFunction((PetscObject)pc, "PCSetCoordinates_C", PCSetCoordinates_FieldSplit));
3041   PetscFunctionReturn(0);
3042 }
3043