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