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