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