xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision edf189ef8e8860d62aa4efa58846ae329f2cd8c2)
1 #define PETSCKSP_DLL
2 
3 /*
4 
5 */
6 #include "private/pcimpl.h"     /*I "petscpc.h" I*/
7 
8 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
9 struct _PC_FieldSplitLink {
10   KSP               ksp;
11   Vec               x,y;
12   PetscInt          nfields;
13   PetscInt          *fields;
14   VecScatter        sctx;
15   IS                is,cis;
16   PetscInt          csize;
17   PC_FieldSplitLink next,previous;
18 };
19 
20 typedef struct {
21   PCCompositeType   type;
22   PetscTruth        defaultsplit;
23   PetscInt          bs;
24   PetscInt          nsplits;
25   Vec               *x,*y,w1,w2;
26   Mat               *pmat;
27   Mat               *Afield; /* the rows of the matrix associated with each field */
28   PetscTruth        issetup;
29   Mat               B,C,schur;   /* only used when Schur complement preconditioning is used */
30   KSP               kspschur;
31   PetscTruth        schurpre;    /* preconditioner for the Schur complement is built from pmat[1] == D */
32   PC_FieldSplitLink head;
33 } PC_FieldSplit;
34 
35 /*
36     Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
37    inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
38    PC you could change this.
39 */
40 #undef __FUNCT__
41 #define __FUNCT__ "PCView_FieldSplit"
42 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
43 {
44   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
45   PetscErrorCode    ierr;
46   PetscTruth        iascii;
47   PetscInt          i,j;
48   PC_FieldSplitLink ilink = jac->head;
49 
50   PetscFunctionBegin;
51   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
52   if (iascii) {
53     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr);
54     ierr = PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr);
55     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
56     for (i=0; i<jac->nsplits; i++) {
57       if (ilink->fields) {
58 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
59 	ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
60 	for (j=0; j<ilink->nfields; j++) {
61 	  if (j > 0) {
62 	    ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
63 	  }
64 	  ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
65 	}
66 	ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
67         ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
68       } else {
69 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr);
70       }
71       ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr);
72       ilink = ilink->next;
73     }
74     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
75   } else {
76     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
77   }
78   PetscFunctionReturn(0);
79 }
80 
81 #undef __FUNCT__
82 #define __FUNCT__ "PCView_FieldSplit_Schur"
83 static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)
84 {
85   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
86   PetscErrorCode    ierr;
87   PetscTruth        iascii;
88   PetscInt          i,j;
89   PC_FieldSplitLink ilink = jac->head;
90   KSP               ksp;
91 
92   PetscFunctionBegin;
93   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
94   if (iascii) {
95     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with Schur preconditioner, blocksize = %D\n",jac->bs);CHKERRQ(ierr);
96     ierr = PetscViewerASCIIPrintf(viewer,"  Split info:\n");CHKERRQ(ierr);
97     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
98     for (i=0; i<jac->nsplits; i++) {
99       if (ilink->fields) {
100 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
101 	ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
102 	for (j=0; j<ilink->nfields; j++) {
103 	  if (j > 0) {
104 	    ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
105 	  }
106 	  ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
107 	}
108 	ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
109         ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
110       } else {
111 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr);
112       }
113       ilink = ilink->next;
114     }
115     ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A block \n");CHKERRQ(ierr);
116     ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
117     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
118     ierr = KSPView(ksp,viewer);CHKERRQ(ierr);
119     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
120     ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = D - C inv(A) B \n");CHKERRQ(ierr);
121     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
122     ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr);
123     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
124     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
125   } else {
126     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
127   }
128   PetscFunctionReturn(0);
129 }
130 
131 #undef __FUNCT__
132 #define __FUNCT__ "PCFieldSplitSetDefaults"
133 static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
134 {
135   PC_FieldSplit     *jac  = (PC_FieldSplit*)pc->data;
136   PetscErrorCode    ierr;
137   PC_FieldSplitLink ilink = jac->head;
138   PetscInt          i = 0,*ifields,nfields;
139   PetscTruth        flg = PETSC_FALSE,*fields,flg2;
140   char              optionname[128];
141 
142   PetscFunctionBegin;
143   if (!ilink) {
144 
145     if (jac->bs <= 0) {
146       if (pc->pmat) {
147         ierr   = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr);
148       } else {
149         jac->bs = 1;
150       }
151     }
152 
153     ierr = PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr);
154     if (!flg) {
155       /* Allow user to set fields from command line,  if bs was known at the time of PCSetFromOptions_FieldSplit()
156          then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
157       flg = PETSC_TRUE; /* switched off automatically if user sets fields manually here */
158       ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);CHKERRQ(ierr);
159       while (PETSC_TRUE) {
160         sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
161         nfields = jac->bs;
162         ierr    = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg2);CHKERRQ(ierr);
163         if (!flg2) break;
164         if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
165         flg = PETSC_FALSE;
166         ierr = PCFieldSplitSetFields(pc,nfields,ifields);CHKERRQ(ierr);
167       }
168       ierr = PetscFree(ifields);CHKERRQ(ierr);
169     }
170 
171     if (flg) {
172       ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr);
173       ierr = PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);CHKERRQ(ierr);
174       ierr = PetscMemzero(fields,jac->bs*sizeof(PetscTruth));CHKERRQ(ierr);
175       while (ilink) {
176 	for (i=0; i<ilink->nfields; i++) {
177 	  fields[ilink->fields[i]] = PETSC_TRUE;
178 	}
179 	ilink = ilink->next;
180       }
181       jac->defaultsplit = PETSC_TRUE;
182       for (i=0; i<jac->bs; i++) {
183 	if (!fields[i]) {
184 	  ierr = PCFieldSplitSetFields(pc,1,&i);CHKERRQ(ierr);
185 	} else {
186 	  jac->defaultsplit = PETSC_FALSE;
187 	}
188       }
189       ierr = PetscFree(fields);CHKERRQ(ierr);
190     }
191   } else if (jac->nsplits == 1) {
192     if (ilink->is) {
193       IS       is2;
194       PetscInt nmin,nmax;
195 
196       ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr);
197       ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr);
198       ierr = PCFieldSplitSetIS(pc,is2);CHKERRQ(ierr);
199       ierr = ISDestroy(is2);CHKERRQ(ierr);
200     } else {
201       SETERRQ(PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
202     }
203   }
204   PetscFunctionReturn(0);
205 }
206 
207 
208 #undef __FUNCT__
209 #define __FUNCT__ "PCSetUp_FieldSplit"
210 static PetscErrorCode PCSetUp_FieldSplit(PC pc)
211 {
212   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
213   PetscErrorCode    ierr;
214   PC_FieldSplitLink ilink;
215   PetscInt          i,nsplit,ccsize;
216   MatStructure      flag = pc->flag;
217   PetscTruth        sorted,getsub;
218 
219   PetscFunctionBegin;
220   ierr   = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr);
221   nsplit = jac->nsplits;
222   ilink  = jac->head;
223 
224   /* get the matrices for each split */
225   if (!jac->issetup) {
226     PetscInt rstart,rend,nslots,bs;
227 
228     jac->issetup = PETSC_TRUE;
229 
230     /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
231     bs     = jac->bs;
232     ierr   = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr);
233     ierr   = MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);CHKERRQ(ierr);
234     nslots = (rend - rstart)/bs;
235     for (i=0; i<nsplit; i++) {
236       if (jac->defaultsplit) {
237         ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr);
238       } else if (!ilink->is) {
239         if (ilink->nfields > 1) {
240           PetscInt   *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
241           ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr);
242           for (j=0; j<nslots; j++) {
243             for (k=0; k<nfields; k++) {
244               ii[nfields*j + k] = rstart + bs*j + fields[k];
245             }
246           }
247           ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,&ilink->is);CHKERRQ(ierr);
248           ierr = PetscFree(ii);CHKERRQ(ierr);
249         } else {
250           ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr);
251         }
252       }
253       ierr = ISGetLocalSize(ilink->is,&ilink->csize);CHKERRQ(ierr);
254       ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr);
255       if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split");
256       ierr = ISAllGather(ilink->is,&ilink->cis);CHKERRQ(ierr);
257       ilink = ilink->next;
258     }
259   }
260 
261   ilink  = jac->head;
262   if (!jac->pmat) {
263     ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr);
264     for (i=0; i<nsplit; i++) {
265       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->cis,ilink->csize,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
266       ilink = ilink->next;
267     }
268   } else {
269     for (i=0; i<nsplit; i++) {
270       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->cis,ilink->csize,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
271       ilink = ilink->next;
272     }
273   }
274 
275   /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
276   ierr = MatHasOperation(pc->mat,MATOP_GET_SUBMATRIX,&getsub);CHKERRQ(ierr);
277   if (getsub && jac->type != PC_COMPOSITE_ADDITIVE  && jac->type != PC_COMPOSITE_SCHUR) {
278     ilink  = jac->head;
279     if (!jac->Afield) {
280       ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr);
281       for (i=0; i<nsplit; i++) {
282 	ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,PETSC_DECIDE,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
283 	ilink = ilink->next;
284       }
285     } else {
286       for (i=0; i<nsplit; i++) {
287 	ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,PETSC_DECIDE,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
288 	ilink = ilink->next;
289       }
290     }
291   }
292 
293   if (jac->type == PC_COMPOSITE_SCHUR) {
294     IS       ccis;
295     PetscInt N,nlocal,nis;
296     if (nsplit != 2) SETERRQ(PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
297 
298     /* need to handle case when one is resetting up the preconditioner */
299     if (jac->schur) {
300       ierr  = MatGetSize(pc->mat,PETSC_NULL,&N);CHKERRQ(ierr);
301       ilink = jac->head;
302       ierr  = ISComplement(ilink->cis,0,N,&ccis);CHKERRQ(ierr);
303       ierr  = ISGetLocalSize(ilink->is,&nis);CHKERRQ(ierr);
304       ierr  = MatGetLocalSize(pc->mat,PETSC_NULL,&nlocal);CHKERRQ(ierr);
305       nlocal = nlocal - nis;
306       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,nlocal,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr);
307       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
308       ilink = ilink->next;
309       ierr  = ISComplement(ilink->cis,0,N,&ccis);CHKERRQ(ierr);
310       ierr  = ISGetLocalSize(ilink->is,&nis);CHKERRQ(ierr);
311       ierr  = MatGetLocalSize(pc->mat,PETSC_NULL,&nlocal);CHKERRQ(ierr);
312       nlocal = nlocal - nis;
313       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,nlocal,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr);
314       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
315       ierr  = MatSchurComplementUpdate(jac->schur,jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);CHKERRQ(ierr);
316       if (jac->schurpre) {
317         ierr  = KSPSetOperators(jac->kspschur,jac->schur,jac->pmat[1],pc->flag);CHKERRQ(ierr);
318       } else {
319         ierr  = KSPSetOperators(jac->kspschur,jac->schur,jac->schur,pc->flag);CHKERRQ(ierr);
320       }
321 
322      } else {
323       KSP ksp;
324 
325       /* extract the B and C matrices */
326       ierr  = MatGetSize(pc->mat,PETSC_NULL,&N);CHKERRQ(ierr);
327       ilink = jac->head;
328       ierr  = ISComplement(ilink->cis,0,N,&ccis);CHKERRQ(ierr);
329       ierr  = ISGetLocalSize(ilink->is,&nis);CHKERRQ(ierr);
330       ierr  = MatGetLocalSize(pc->mat,PETSC_NULL,&nlocal);CHKERRQ(ierr);
331       nlocal = nlocal - nis;
332       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,nlocal,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr);
333       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
334       ilink = ilink->next;
335       ierr  = ISComplement(ilink->cis,0,N,&ccis);CHKERRQ(ierr);
336       ierr  = ISGetLocalSize(ilink->is,&nis);CHKERRQ(ierr);
337       ierr  = MatGetLocalSize(pc->mat,PETSC_NULL,&nlocal);CHKERRQ(ierr);
338       nlocal = nlocal - nis;
339       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,nlocal,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr);
340       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
341       ierr  = MatCreateSchurComplement(jac->pmat[0],jac->B,jac->C,jac->pmat[1],&jac->schur);CHKERRQ(ierr);
342       ierr  = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
343       ierr  = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);CHKERRQ(ierr);
344       ierr  = MatSetFromOptions(jac->schur);CHKERRQ(ierr);
345 
346       ierr  = KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);CHKERRQ(ierr);
347       ierr  = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr);
348       if (jac->schurpre) {
349         ierr  = KSPSetOperators(jac->kspschur,jac->schur,jac->pmat[1],DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
350       } else {
351         ierr  = KSPSetOperators(jac->kspschur,jac->schur,jac->schur,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
352       }
353       ierr  = KSPSetOptionsPrefix(jac->kspschur,((PetscObject)pc)->prefix);CHKERRQ(ierr);
354       ierr  = KSPAppendOptionsPrefix(jac->kspschur,"fieldsplit_1_");CHKERRQ(ierr);
355       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
356       ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr);
357 
358       ierr = PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);CHKERRQ(ierr);
359       ierr = MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);CHKERRQ(ierr);
360       ierr = MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);CHKERRQ(ierr);
361       ilink = jac->head;
362       ilink->x = jac->x[0]; ilink->y = jac->y[0];
363       ilink = ilink->next;
364       ilink->x = jac->x[1]; ilink->y = jac->y[1];
365     }
366   } else {
367     /* set up the individual PCs */
368     i    = 0;
369     ilink = jac->head;
370     while (ilink) {
371       ierr = KSPSetOperators(ilink->ksp,jac->pmat[i],jac->pmat[i],flag);CHKERRQ(ierr);
372       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
373       ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);
374       ierr = KSPSetUp(ilink->ksp);CHKERRQ(ierr);
375       i++;
376       ilink = ilink->next;
377     }
378 
379     /* create work vectors for each split */
380     if (!jac->x) {
381       ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr);
382       ilink = jac->head;
383       for (i=0; i<nsplit; i++) {
384         Vec *vl,*vr;
385 
386         ierr      = KSPGetVecs(ilink->ksp,1,&vr,1,&vl);CHKERRQ(ierr);
387         ilink->x  = *vr;
388         ilink->y  = *vl;
389         ierr      = PetscFree(vr);CHKERRQ(ierr);
390         ierr      = PetscFree(vl);CHKERRQ(ierr);
391         jac->x[i] = ilink->x;
392         jac->y[i] = ilink->y;
393         ilink     = ilink->next;
394       }
395     }
396   }
397 
398 
399   if (1) {
400     Vec xtmp;
401 
402     /* compute scatter contexts needed by multiplicative versions and non-default splits */
403 
404     ilink = jac->head;
405     ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr);
406     for (i=0; i<nsplit; i++) {
407       ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);CHKERRQ(ierr);
408       ilink = ilink->next;
409     }
410     ierr = VecDestroy(xtmp);CHKERRQ(ierr);
411   }
412   PetscFunctionReturn(0);
413 }
414 
415 #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
416     (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
417      VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
418      KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
419      VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
420      VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
421 
422 #undef __FUNCT__
423 #define __FUNCT__ "PCApply_FieldSplit_Schur"
424 static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
425 {
426   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
427   PetscErrorCode    ierr;
428   KSP               ksp;
429   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
430 
431   PetscFunctionBegin;
432   ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
433 
434   ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
435   ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
436   ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
437   ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr);
438   ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr);
439   ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
440   ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
441 
442   ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
443   ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
444   ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
445 
446   ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr);
447   ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr);
448   ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
449   ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
450   ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
451 
452   PetscFunctionReturn(0);
453 }
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "PCApply_FieldSplit"
457 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
458 {
459   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
460   PetscErrorCode    ierr;
461   PC_FieldSplitLink ilink = jac->head;
462   PetscInt          bs,cnt;
463 
464   PetscFunctionBegin;
465   CHKMEMQ;
466   ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
467   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
468   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
469 
470   if (jac->type == PC_COMPOSITE_ADDITIVE) {
471     if (jac->defaultsplit) {
472       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
473       while (ilink) {
474         ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
475         ilink = ilink->next;
476       }
477       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
478     } else {
479       ierr = VecSet(y,0.0);CHKERRQ(ierr);
480       while (ilink) {
481         ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
482         ilink = ilink->next;
483       }
484     }
485   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
486     if (!jac->w1) {
487       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
488       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
489     }
490     ierr = VecSet(y,0.0);CHKERRQ(ierr);
491     ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
492     cnt = 1;
493     while (ilink->next) {
494       ilink = ilink->next;
495       if (jac->Afield) {
496         /* compute the residual only over the part of the vector needed */
497         ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr);
498         ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr);
499         ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
500         ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
501         ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
502         ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
503         ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
504       } else {
505         /* compute the residual over the entire vector */
506 	ierr = MatMult(pc->mat,y,jac->w1);CHKERRQ(ierr);
507 	ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
508 	ierr = FieldSplitSplitSolveAdd(ilink,jac->w2,y);CHKERRQ(ierr);
509       }
510     }
511     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
512       cnt -= 2;
513       while (ilink->previous) {
514         ilink = ilink->previous;
515         if (jac->Afield) {
516 	  /* compute the residual only over the part of the vector needed */
517 	  ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr);
518 	  ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr);
519 	  ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
520 	  ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
521 	  ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
522 	  ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
523 	  ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
524         } else {
525 	  ierr  = MatMult(pc->mat,y,jac->w1);CHKERRQ(ierr);
526 	  ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
527 	  ierr  = FieldSplitSplitSolveAdd(ilink,jac->w2,y);CHKERRQ(ierr);
528         }
529       }
530     }
531   } else SETERRQ1(PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
532   CHKMEMQ;
533   PetscFunctionReturn(0);
534 }
535 
536 #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
537     (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
538      VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
539      KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
540      VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
541      VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
542 
543 #undef __FUNCT__
544 #define __FUNCT__ "PCApply_FieldSplit"
545 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
546 {
547   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
548   PetscErrorCode    ierr;
549   PC_FieldSplitLink ilink = jac->head;
550   PetscInt          bs;
551 
552   PetscFunctionBegin;
553   CHKMEMQ;
554   ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
555   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
556   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
557 
558   if (jac->type == PC_COMPOSITE_ADDITIVE) {
559     if (jac->defaultsplit) {
560       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
561       while (ilink) {
562 	ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
563 	ilink = ilink->next;
564       }
565       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
566     } else {
567       ierr = VecSet(y,0.0);CHKERRQ(ierr);
568       while (ilink) {
569         ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
570 	ilink = ilink->next;
571       }
572     }
573   } else {
574     if (!jac->w1) {
575       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
576       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
577     }
578     ierr = VecSet(y,0.0);CHKERRQ(ierr);
579     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
580       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
581       while (ilink->next) {
582         ilink = ilink->next;
583         ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
584         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
585         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
586       }
587       while (ilink->previous) {
588         ilink = ilink->previous;
589         ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
590         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
591         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
592       }
593     } else {
594       while (ilink->next) {   /* get to last entry in linked list */
595 	ilink = ilink->next;
596       }
597       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
598       while (ilink->previous) {
599 	ilink = ilink->previous;
600 	ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
601 	ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
602 	ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
603       }
604     }
605   }
606   CHKMEMQ;
607   PetscFunctionReturn(0);
608 }
609 
610 #undef __FUNCT__
611 #define __FUNCT__ "PCDestroy_FieldSplit"
612 static PetscErrorCode PCDestroy_FieldSplit(PC pc)
613 {
614   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
615   PetscErrorCode    ierr;
616   PC_FieldSplitLink ilink = jac->head,next;
617 
618   PetscFunctionBegin;
619   while (ilink) {
620     ierr = KSPDestroy(ilink->ksp);CHKERRQ(ierr);
621     if (ilink->x) {ierr = VecDestroy(ilink->x);CHKERRQ(ierr);}
622     if (ilink->y) {ierr = VecDestroy(ilink->y);CHKERRQ(ierr);}
623     if (ilink->sctx) {ierr = VecScatterDestroy(ilink->sctx);CHKERRQ(ierr);}
624     if (ilink->is) {ierr = ISDestroy(ilink->is);CHKERRQ(ierr);}
625     if (ilink->cis) {ierr = ISDestroy(ilink->cis);CHKERRQ(ierr);}
626     next = ilink->next;
627     ierr = PetscFree(ilink->fields);CHKERRQ(ierr);
628     ierr = PetscFree(ilink);CHKERRQ(ierr);
629     ilink = next;
630   }
631   ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr);
632   if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);}
633   if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);}
634   if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);}
635   if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);}
636   if (jac->schur) {ierr = MatDestroy(jac->schur);CHKERRQ(ierr);}
637   if (jac->B) {ierr = MatDestroy(jac->B);CHKERRQ(ierr);}
638   if (jac->C) {ierr = MatDestroy(jac->C);CHKERRQ(ierr);}
639   ierr = PetscFree(jac);CHKERRQ(ierr);
640   PetscFunctionReturn(0);
641 }
642 
643 #undef __FUNCT__
644 #define __FUNCT__ "PCSetFromOptions_FieldSplit"
645 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
646 {
647   PetscErrorCode  ierr;
648   PetscInt        i = 0,nfields,*fields,bs;
649   PetscTruth      flg,set;
650   char            optionname[128];
651   PC_FieldSplit   *jac = (PC_FieldSplit*)pc->data;
652   PCCompositeType ctype;
653 
654   PetscFunctionBegin;
655   ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr);
656   ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr);
657   if (flg) {
658     ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr);
659   }
660 
661   ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);CHKERRQ(ierr);
662   if (flg) {
663     ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr);
664   }
665 
666   if (jac->bs > 0) {
667     /* only allow user to set fields from command line if bs is already known.
668        otherwise user can set them in PCFieldSplitSetDefaults() */
669     ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&fields);CHKERRQ(ierr);
670     while (PETSC_TRUE) {
671       sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
672       nfields = jac->bs;
673       ierr    = PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);CHKERRQ(ierr);
674       if (!flg) break;
675       if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
676       ierr = PCFieldSplitSetFields(pc,nfields,fields);CHKERRQ(ierr);
677     }
678     ierr = PetscFree(fields);CHKERRQ(ierr);
679   }
680   ierr = PetscOptionsTruth("-pc_fieldsplit_schur_precondition","Build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",jac->schurpre,&flg,&set);CHKERRQ(ierr);
681   if (set) {
682     ierr = PCFieldSplitSchurPrecondition(pc,flg);CHKERRQ(ierr);
683   }
684   ierr = PetscOptionsTail();CHKERRQ(ierr);
685   PetscFunctionReturn(0);
686 }
687 
688 /*------------------------------------------------------------------------------------*/
689 
690 EXTERN_C_BEGIN
691 #undef __FUNCT__
692 #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit"
693 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields)
694 {
695   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
696   PetscErrorCode    ierr;
697   PC_FieldSplitLink ilink,next = jac->head;
698   char              prefix[128];
699   PetscInt          i;
700 
701   PetscFunctionBegin;
702   if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested");
703   for (i=0; i<n; i++) {
704     if (fields[i] >= jac->bs) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
705     if (fields[i] < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
706   }
707   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
708   ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields);CHKERRQ(ierr);
709   ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr);
710   ilink->nfields = n;
711   ilink->next    = PETSC_NULL;
712   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
713   ierr           = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
714   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
715 
716   if (((PetscObject)pc)->prefix) {
717     sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
718   } else {
719     sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
720   }
721   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
722 
723   if (!next) {
724     jac->head       = ilink;
725     ilink->previous = PETSC_NULL;
726   } else {
727     while (next->next) {
728       next = next->next;
729     }
730     next->next      = ilink;
731     ilink->previous = next;
732   }
733   jac->nsplits++;
734   PetscFunctionReturn(0);
735 }
736 EXTERN_C_END
737 
738 EXTERN_C_BEGIN
739 #undef __FUNCT__
740 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit_Schur"
741 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
742 {
743   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
744   PetscErrorCode    ierr;
745   PetscInt          cnt = 0;
746   PC_FieldSplitLink ilink = jac->head;
747 
748   PetscFunctionBegin;
749   ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr);
750   ierr = MatSchurComplementGetKSP(jac->schur,*subksp);CHKERRQ(ierr);
751   (*subksp)[1] = jac->kspschur;
752   PetscFunctionReturn(0);
753 }
754 EXTERN_C_END
755 
756 EXTERN_C_BEGIN
757 #undef __FUNCT__
758 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit"
759 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
760 {
761   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
762   PetscErrorCode    ierr;
763   PetscInt          cnt = 0;
764   PC_FieldSplitLink ilink = jac->head;
765 
766   PetscFunctionBegin;
767   ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr);
768   while (ilink) {
769     (*subksp)[cnt++] = ilink->ksp;
770     ilink = ilink->next;
771   }
772   if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits);
773   *n = jac->nsplits;
774   PetscFunctionReturn(0);
775 }
776 EXTERN_C_END
777 
778 EXTERN_C_BEGIN
779 #undef __FUNCT__
780 #define __FUNCT__ "PCFieldSplitSetIS_FieldSplit"
781 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS_FieldSplit(PC pc,IS is)
782 {
783   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
784   PetscErrorCode    ierr;
785   PC_FieldSplitLink ilink, next = jac->head;
786   char              prefix[128];
787 
788   PetscFunctionBegin;
789   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
790   ilink->is      = is;
791   ierr           = PetscObjectReference((PetscObject)is);CHKERRQ(ierr);
792   ilink->next    = PETSC_NULL;
793   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
794   ierr           = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
795   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
796 
797   if (((PetscObject)pc)->prefix) {
798     sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
799   } else {
800     sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
801   }
802   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
803 
804   if (!next) {
805     jac->head       = ilink;
806     ilink->previous = PETSC_NULL;
807   } else {
808     while (next->next) {
809       next = next->next;
810     }
811     next->next      = ilink;
812     ilink->previous = next;
813   }
814   jac->nsplits++;
815 
816   PetscFunctionReturn(0);
817 }
818 EXTERN_C_END
819 
820 #undef __FUNCT__
821 #define __FUNCT__ "PCFieldSplitSetFields"
822 /*@
823     PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
824 
825     Collective on PC
826 
827     Input Parameters:
828 +   pc  - the preconditioner context
829 .   n - the number of fields in this split
830 .   fields - the fields in this split
831 
832     Level: intermediate
833 
834     Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
835 
836      The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
837      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
838      0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
839      where the numbered entries indicate what is in the field.
840 
841 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
842 
843 @*/
844 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields)
845 {
846   PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *);
847 
848   PetscFunctionBegin;
849   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
850   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);CHKERRQ(ierr);
851   if (f) {
852     ierr = (*f)(pc,n,fields);CHKERRQ(ierr);
853   }
854   PetscFunctionReturn(0);
855 }
856 
857 #undef __FUNCT__
858 #define __FUNCT__ "PCFieldSplitSetIS"
859 /*@
860     PCFieldSplitSetIS - Sets the exact elements for field
861 
862     Collective on PC
863 
864     Input Parameters:
865 +   pc  - the preconditioner context
866 .   is - the index set that defines the vector elements in this field
867 
868 
869     Notes: Use PCFieldSplitSetFields(), for fields defined by strided types.
870 
871     Level: intermediate
872 
873 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
874 
875 @*/
876 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS(PC pc,IS is)
877 {
878   PetscErrorCode ierr,(*f)(PC,IS);
879 
880   PetscFunctionBegin;
881   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
882   PetscValidHeaderSpecific(is,IS_COOKIE,1);
883   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetIS_C",(void (**)(void))&f);CHKERRQ(ierr);
884   if (f) {
885     ierr = (*f)(pc,is);CHKERRQ(ierr);
886   }
887   PetscFunctionReturn(0);
888 }
889 
890 #undef __FUNCT__
891 #define __FUNCT__ "PCFieldSplitSetBlockSize"
892 /*@
893     PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
894       fieldsplit preconditioner. If not set the matrix block size is used.
895 
896     Collective on PC
897 
898     Input Parameters:
899 +   pc  - the preconditioner context
900 -   bs - the block size
901 
902     Level: intermediate
903 
904 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
905 
906 @*/
907 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
908 {
909   PetscErrorCode ierr,(*f)(PC,PetscInt);
910 
911   PetscFunctionBegin;
912   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
913   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",(void (**)(void))&f);CHKERRQ(ierr);
914   if (f) {
915     ierr = (*f)(pc,bs);CHKERRQ(ierr);
916   }
917   PetscFunctionReturn(0);
918 }
919 
920 #undef __FUNCT__
921 #define __FUNCT__ "PCFieldSplitGetSubKSP"
922 /*@C
923    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
924 
925    Collective on KSP
926 
927    Input Parameter:
928 .  pc - the preconditioner context
929 
930    Output Parameters:
931 +  n - the number of split
932 -  pc - the array of KSP contexts
933 
934    Note:
935    After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
936    (not the KSP just the array that contains them).
937 
938    You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
939 
940    Level: advanced
941 
942 .seealso: PCFIELDSPLIT
943 @*/
944 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
945 {
946   PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **);
947 
948   PetscFunctionBegin;
949   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
950   PetscValidIntPointer(n,2);
951   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);CHKERRQ(ierr);
952   if (f) {
953     ierr = (*f)(pc,n,subksp);CHKERRQ(ierr);
954   } else {
955     SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC");
956   }
957   PetscFunctionReturn(0);
958 }
959 
960 #undef __FUNCT__
961 #define __FUNCT__ "PCFieldSplitSchurPrecondition"
962 /*@
963     PCFieldSplitSchurPrecondition - Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
964       D matrix. Otherwise no preconditioner is used.
965 
966     Collective on PC
967 
968     Input Parameters:
969 +   pc  - the preconditioner context
970 -   flg - build the preconditioner
971 
972     Options Database:
973 .     -pc_fieldsplit_schur_precondition <true,false> default is true
974 
975     Level: intermediate
976 
977     Notes: What should we do if the user wants to provide a different matrix (like a mass matrix) to use to build the preconditioner
978 
979 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFIELDSPLIT
980 
981 @*/
982 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSchurPrecondition(PC pc,PetscTruth flg)
983 {
984   PetscErrorCode ierr,(*f)(PC,PetscTruth);
985 
986   PetscFunctionBegin;
987   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
988   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSchurPrecondition_C",(void (**)(void))&f);CHKERRQ(ierr);
989   if (f) {
990     ierr = (*f)(pc,flg);CHKERRQ(ierr);
991   }
992   PetscFunctionReturn(0);
993 }
994 
995 EXTERN_C_BEGIN
996 #undef __FUNCT__
997 #define __FUNCT__ "PCFieldSplitSchurPrecondition_FieldSplit"
998 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PetscTruth flg)
999 {
1000   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1001 
1002   PetscFunctionBegin;
1003   jac->schurpre = flg;
1004   PetscFunctionReturn(0);
1005 }
1006 EXTERN_C_END
1007 
1008 EXTERN_C_BEGIN
1009 #undef __FUNCT__
1010 #define __FUNCT__ "PCFieldSplitSetType_FieldSplit"
1011 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
1012 {
1013   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1014   PetscErrorCode ierr;
1015 
1016   PetscFunctionBegin;
1017   jac->type = type;
1018   if (type == PC_COMPOSITE_SCHUR) {
1019     pc->ops->apply = PCApply_FieldSplit_Schur;
1020     pc->ops->view  = PCView_FieldSplit_Schur;
1021     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);CHKERRQ(ierr);
1022     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);CHKERRQ(ierr);
1023 
1024   } else {
1025     pc->ops->apply = PCApply_FieldSplit;
1026     pc->ops->view  = PCView_FieldSplit;
1027     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
1028     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);CHKERRQ(ierr);
1029   }
1030   PetscFunctionReturn(0);
1031 }
1032 EXTERN_C_END
1033 
1034 EXTERN_C_BEGIN
1035 #undef __FUNCT__
1036 #define __FUNCT__ "PCFieldSplitSetBlockSize_FieldSplit"
1037 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
1038 {
1039   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1040 
1041   PetscFunctionBegin;
1042   if (bs < 1) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
1043   if (jac->bs > 0 && jac->bs != bs) SETERRQ2(PETSC_ERR_ARG_WRONGSTATE,"Cannot change fieldsplit blocksize from %D to %D after it has been set",jac->bs,bs);
1044   jac->bs = bs;
1045   PetscFunctionReturn(0);
1046 }
1047 EXTERN_C_END
1048 
1049 #undef __FUNCT__
1050 #define __FUNCT__ "PCFieldSplitSetType"
1051 /*@
1052    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
1053 
1054    Collective on PC
1055 
1056    Input Parameter:
1057 .  pc - the preconditioner context
1058 .  type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE
1059 
1060    Options Database Key:
1061 .  -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets fieldsplit preconditioner type
1062 
1063    Level: Developer
1064 
1065 .keywords: PC, set, type, composite preconditioner, additive, multiplicative
1066 
1067 .seealso: PCCompositeSetType()
1068 
1069 @*/
1070 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType(PC pc,PCCompositeType type)
1071 {
1072   PetscErrorCode ierr,(*f)(PC,PCCompositeType);
1073 
1074   PetscFunctionBegin;
1075   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
1076   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);CHKERRQ(ierr);
1077   if (f) {
1078     ierr = (*f)(pc,type);CHKERRQ(ierr);
1079   }
1080   PetscFunctionReturn(0);
1081 }
1082 
1083 /* -------------------------------------------------------------------------------------*/
1084 /*MC
1085    PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
1086                   fields or groups of fields
1087 
1088 
1089      To set options on the solvers for each block append -fieldsplit_ to all the PC
1090         options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
1091 
1092      To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
1093          and set the options directly on the resulting KSP object
1094 
1095    Level: intermediate
1096 
1097    Options Database Keys:
1098 +   -pc_splitfield_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
1099 .   -pc_splitfield_default - automatically add any fields to additional splits that have not
1100                               been supplied explicitly by -pc_splitfield_%d_fields
1101 .   -pc_splitfield_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
1102 .    -pc_splitfield_type <additive,multiplicative,schur,symmetric_multiplicative>
1103 .    -pc_fieldsplit_schur_precondition <true,false> default is true
1104 
1105 -    Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
1106      for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
1107 
1108 
1109    Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1110      to define a field by an arbitrary collection of entries.
1111 
1112       If no fields are set the default is used. The fields are defined by entries strided by bs,
1113       beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1114       if this is not called the block size defaults to the blocksize of the second matrix passed
1115       to KSPSetOperators()/PCSetOperators().
1116 
1117       Currently for the multiplicative version, the updated residual needed for the next field
1118      solve is computed via a matrix vector product over the entire array. An optimization would be
1119      to update the residual only for the part of the right hand side associated with the next field
1120      solve. (This would involve more MatGetSubMatrix() calls or some other mechanism to compute the
1121      part of the matrix needed to just update part of the residual).
1122 
1123      For the Schur complement preconditioner if J = ( A B )
1124                                                     ( C D )
1125      the preconditioner is
1126               (I   -B inv(A)) ( inv(A)   0    ) (I         0  )
1127               (0    I       ) (   0    inv(S) ) (-C inv(A) I  )
1128      where the action of inv(A) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1129      inv(S) is computed using the KSP solver with prefix -schur_. For PCFieldSplitGetKSP() when field number is
1130      0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1131      D is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
1132      option.
1133 
1134      If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1135      is used automatically for a second block.
1136 
1137    Concepts: physics based preconditioners
1138 
1139 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
1140            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1141 M*/
1142 
1143 EXTERN_C_BEGIN
1144 #undef __FUNCT__
1145 #define __FUNCT__ "PCCreate_FieldSplit"
1146 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_FieldSplit(PC pc)
1147 {
1148   PetscErrorCode ierr;
1149   PC_FieldSplit  *jac;
1150 
1151   PetscFunctionBegin;
1152   ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr);
1153   jac->bs        = -1;
1154   jac->nsplits   = 0;
1155   jac->type      = PC_COMPOSITE_MULTIPLICATIVE;
1156   jac->schurpre  = PETSC_TRUE;
1157 
1158   pc->data     = (void*)jac;
1159 
1160   pc->ops->apply             = PCApply_FieldSplit;
1161   pc->ops->applytranspose    = PCApplyTranspose_FieldSplit;
1162   pc->ops->setup             = PCSetUp_FieldSplit;
1163   pc->ops->destroy           = PCDestroy_FieldSplit;
1164   pc->ops->setfromoptions    = PCSetFromOptions_FieldSplit;
1165   pc->ops->view              = PCView_FieldSplit;
1166   pc->ops->applyrichardson   = 0;
1167 
1168   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
1169                     PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
1170   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
1171                     PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr);
1172   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1173                     PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr);
1174   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
1175                     PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr);
1176   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
1177                     PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr);
1178   PetscFunctionReturn(0);
1179 }
1180 EXTERN_C_END
1181 
1182 
1183