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