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