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