xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision 6add55ec78f3524b03daef384a0e0f82e1349209)
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;              /* additive or multiplicative */
22   PetscTruth        defaultsplit;
23   PetscInt          bs;
24   PetscInt          nsplits;
25   Vec               *x,*y,w1,w2;
26   Mat               *pmat;
27   PetscTruth        issetup;
28   PC_FieldSplitLink head;
29 } PC_FieldSplit;
30 
31 /*
32     Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
33    inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
34    PC you could change this.
35 */
36 #undef __FUNCT__
37 #define __FUNCT__ "PCView_FieldSplit"
38 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
39 {
40   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
41   PetscErrorCode    ierr;
42   PetscTruth        iascii;
43   PetscInt          i,j;
44   PC_FieldSplitLink ilink = jac->head;
45 
46   PetscFunctionBegin;
47   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
48   if (iascii) {
49     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr);
50     ierr = PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr);
51     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
52     for (i=0; i<jac->nsplits; i++) {
53       ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
54       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
55       for (j=0; j<ilink->nfields; j++) {
56         if (j > 0) {
57           ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
58         }
59         ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
60       }
61       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
62       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
63       ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr);
64       ilink = ilink->next;
65     }
66     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
67   } else {
68     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "PCFieldSplitSetDefaults"
75 static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
76 {
77   PC_FieldSplit     *jac  = (PC_FieldSplit*)pc->data;
78   PetscErrorCode    ierr;
79   PC_FieldSplitLink ilink = jac->head;
80   PetscInt          i;
81   PetscTruth        flg = PETSC_FALSE,*fields;
82 
83   PetscFunctionBegin;
84   ierr = PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr);
85   if (!ilink || flg) {
86     ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr);
87     if (jac->bs <= 0) {
88       if (pc->pmat) {
89         ierr   = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr);
90       } else {
91         jac->bs = 1;
92       }
93     }
94     ierr = PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);CHKERRQ(ierr);
95     ierr = PetscMemzero(fields,jac->bs*sizeof(PetscTruth));CHKERRQ(ierr);
96     while (ilink) {
97       for (i=0; i<ilink->nfields; i++) {
98         fields[ilink->fields[i]] = PETSC_TRUE;
99       }
100       ilink = ilink->next;
101     }
102     jac->defaultsplit = PETSC_TRUE;
103     for (i=0; i<jac->bs; i++) {
104       if (!fields[i]) {
105 	ierr = PCFieldSplitSetFields(pc,1,&i);CHKERRQ(ierr);
106       } else {
107         jac->defaultsplit = PETSC_FALSE;
108       }
109     }
110   }
111   PetscFunctionReturn(0);
112 }
113 
114 
115 #undef __FUNCT__
116 #define __FUNCT__ "PCSetUp_FieldSplit"
117 static PetscErrorCode PCSetUp_FieldSplit(PC pc)
118 {
119   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
120   PetscErrorCode    ierr;
121   PC_FieldSplitLink ilink;
122   PetscInt          i,nsplit,ccsize;
123   MatStructure      flag = pc->flag;
124   PetscTruth        sorted;
125 
126   PetscFunctionBegin;
127   ierr   = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr);
128   nsplit = jac->nsplits;
129   ilink  = jac->head;
130 
131   /* get the matrices for each split */
132   if (!jac->issetup) {
133     PetscInt rstart,rend,nslots,bs;
134 
135     jac->issetup = PETSC_TRUE;
136 
137     /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
138     bs     = jac->bs;
139     ierr   = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr);
140     ierr   = MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);CHKERRQ(ierr);
141     nslots = (rend - rstart)/bs;
142     for (i=0; i<nsplit; i++) {
143       if (jac->defaultsplit) {
144         ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr);
145         ilink->csize = ccsize/nsplit;
146       } else if (!ilink->is) {
147         if (ilink->nfields > 1) {
148           PetscInt   *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
149           ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr);
150           for (j=0; j<nslots; j++) {
151             for (k=0; k<nfields; k++) {
152               ii[nfields*j + k] = rstart + bs*j + fields[k];
153             }
154           }
155           ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,&ilink->is);CHKERRQ(ierr);
156           ierr = PetscFree(ii);CHKERRQ(ierr);
157         } else {
158           ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr);
159         }
160         ilink->csize = (ccsize/bs)*ilink->nfields;
161         ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr);
162         if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split");
163       }
164       ierr  = ISAllGather(ilink->is,&ilink->cis);CHKERRQ(ierr);
165       ilink = ilink->next;
166     }
167   }
168 
169   ilink  = jac->head;
170   if (!jac->pmat) {
171     ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr);
172     for (i=0; i<nsplit; i++) {
173       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->cis,ilink->csize,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
174       ilink = ilink->next;
175     }
176   } else {
177     for (i=0; i<nsplit; i++) {
178       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->cis,ilink->csize,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
179       ilink = ilink->next;
180     }
181   }
182 
183   /* set up the individual PCs */
184   i    = 0;
185   ilink = jac->head;
186   while (ilink) {
187     ierr = KSPSetOperators(ilink->ksp,jac->pmat[i],jac->pmat[i],flag);CHKERRQ(ierr);
188     ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);
189     ierr = KSPSetUp(ilink->ksp);CHKERRQ(ierr);
190     i++;
191     ilink = ilink->next;
192   }
193 
194   /* create work vectors for each split */
195   if (!jac->x) {
196     Vec xtmp;
197     ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr);
198     ilink = jac->head;
199     for (i=0; i<nsplit; i++) {
200       Vec *vl,*vr;
201 
202       ierr      = KSPGetVecs(ilink->ksp,1,&vr,1,&vl);CHKERRQ(ierr);
203       ilink->x  = *vr;
204       ilink->y  = *vl;
205       ierr      = PetscFree(vr);CHKERRQ(ierr);
206       ierr      = PetscFree(vl);CHKERRQ(ierr);
207       jac->x[i] = ilink->x;
208       jac->y[i] = ilink->y;
209       ilink     = ilink->next;
210     }
211     /* compute scatter contexts needed by multiplicative versions and non-default splits */
212 
213     ilink = jac->head;
214     ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr);
215     for (i=0; i<nsplit; i++) {
216       ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);CHKERRQ(ierr);
217       ilink = ilink->next;
218     }
219     ierr = VecDestroy(xtmp);CHKERRQ(ierr);
220   }
221   PetscFunctionReturn(0);
222 }
223 
224 #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
225     (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
226      VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
227      KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
228      VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
229      VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
230 
231 #undef __FUNCT__
232 #define __FUNCT__ "PCApply_FieldSplit"
233 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
234 {
235   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
236   PetscErrorCode    ierr;
237   PC_FieldSplitLink ilink = jac->head;
238   PetscInt          bs;
239 
240   PetscFunctionBegin;
241   CHKMEMQ;
242   ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
243   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
244   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
245 
246   if (jac->type == PC_COMPOSITE_ADDITIVE) {
247     if (jac->defaultsplit) {
248       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
249       while (ilink) {
250 	ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
251 	ilink = ilink->next;
252       }
253       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
254     } else {
255       ierr = VecSet(y,0.0);CHKERRQ(ierr);
256       while (ilink) {
257         ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
258 	ilink = ilink->next;
259       }
260     }
261   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
262     if (!jac->w1) {
263       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
264       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
265     }
266     ierr = VecSet(y,0.0);CHKERRQ(ierr);
267     ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
268     while (ilink->next) {
269       ilink = ilink->next;
270       ierr  = MatMult(pc->pmat,y,jac->w1);CHKERRQ(ierr);
271       ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
272       ierr  = FieldSplitSplitSolveAdd(ilink,jac->w2,y);CHKERRQ(ierr);
273     }
274     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
275       while (ilink->previous) {
276         ilink = ilink->previous;
277         ierr  = MatMult(pc->pmat,y,jac->w1);CHKERRQ(ierr);
278         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
279         ierr  = FieldSplitSplitSolveAdd(ilink,jac->w2,y);CHKERRQ(ierr);
280       }
281     }
282     } else SETERRQ1(PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
283   CHKMEMQ;
284   PetscFunctionReturn(0);
285 }
286 
287 #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
288     (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
289      VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
290      KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
291      VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
292      VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
293 
294 #undef __FUNCT__
295 #define __FUNCT__ "PCApply_FieldSplit"
296 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
297 {
298   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
299   PetscErrorCode    ierr;
300   PC_FieldSplitLink ilink = jac->head;
301   PetscInt          bs;
302 
303   PetscFunctionBegin;
304   CHKMEMQ;
305   ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
306   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
307   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
308 
309   if (jac->type == PC_COMPOSITE_ADDITIVE) {
310     if (jac->defaultsplit) {
311       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
312       while (ilink) {
313 	ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
314 	ilink = ilink->next;
315       }
316       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
317     } else {
318       ierr = VecSet(y,0.0);CHKERRQ(ierr);
319       while (ilink) {
320         ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
321 	ilink = ilink->next;
322       }
323     }
324   } else {
325     if (!jac->w1) {
326       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
327       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
328     }
329     ierr = VecSet(y,0.0);CHKERRQ(ierr);
330     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
331       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
332       while (ilink->next) {
333         ilink = ilink->next;
334         ierr  = MatMultTranspose(pc->pmat,y,jac->w1);CHKERRQ(ierr);
335         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
336         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
337       }
338       while (ilink->previous) {
339         ilink = ilink->previous;
340         ierr  = MatMultTranspose(pc->pmat,y,jac->w1);CHKERRQ(ierr);
341         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
342         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
343       }
344     } else {
345       while (ilink->next) {   /* get to last entry in linked list */
346 	ilink = ilink->next;
347       }
348       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
349       while (ilink->previous) {
350 	ilink = ilink->previous;
351 	ierr  = MatMultTranspose(pc->pmat,y,jac->w1);CHKERRQ(ierr);
352 	ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
353 	ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
354       }
355     }
356   }
357   CHKMEMQ;
358   PetscFunctionReturn(0);
359 }
360 
361 #undef __FUNCT__
362 #define __FUNCT__ "PCDestroy_FieldSplit"
363 static PetscErrorCode PCDestroy_FieldSplit(PC pc)
364 {
365   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
366   PetscErrorCode    ierr;
367   PC_FieldSplitLink ilink = jac->head,next;
368 
369   PetscFunctionBegin;
370   while (ilink) {
371     ierr = KSPDestroy(ilink->ksp);CHKERRQ(ierr);
372     if (ilink->x) {ierr = VecDestroy(ilink->x);CHKERRQ(ierr);}
373     if (ilink->y) {ierr = VecDestroy(ilink->y);CHKERRQ(ierr);}
374     if (ilink->sctx) {ierr = VecScatterDestroy(ilink->sctx);CHKERRQ(ierr);}
375     if (ilink->is) {ierr = ISDestroy(ilink->is);CHKERRQ(ierr);}
376     if (ilink->cis) {ierr = ISDestroy(ilink->cis);CHKERRQ(ierr);}
377     next = ilink->next;
378     ierr = PetscFree(ilink->fields);CHKERRQ(ierr);
379     ierr = PetscFree(ilink);CHKERRQ(ierr);
380     ilink = next;
381   }
382   ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr);
383   if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);}
384   if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);}
385   if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);}
386   ierr = PetscFree(jac);CHKERRQ(ierr);
387   PetscFunctionReturn(0);
388 }
389 
390 #undef __FUNCT__
391 #define __FUNCT__ "PCSetFromOptions_FieldSplit"
392 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
393 {
394   PetscErrorCode ierr;
395   PetscInt       i = 0,nfields,*fields,bs;
396   PetscTruth     flg;
397   char           optionname[128];
398   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
399 
400   PetscFunctionBegin;
401   ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr);
402   ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr);
403   if (flg) {
404     ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr);
405   }
406   if (jac->bs <= 0) {
407 
408     ierr = PCFieldSplitSetBlockSize(pc,1);CHKERRQ(ierr);
409   }
410   ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);CHKERRQ(ierr);
411   ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&fields);CHKERRQ(ierr);
412   while (PETSC_TRUE) {
413     sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
414     nfields = jac->bs;
415     ierr    = PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);CHKERRQ(ierr);
416     if (!flg) break;
417     if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
418     ierr = PCFieldSplitSetFields(pc,nfields,fields);CHKERRQ(ierr);
419   }
420   ierr = PetscFree(fields);CHKERRQ(ierr);
421   ierr = PetscOptionsTail();CHKERRQ(ierr);
422   PetscFunctionReturn(0);
423 }
424 
425 /*------------------------------------------------------------------------------------*/
426 
427 EXTERN_C_BEGIN
428 #undef __FUNCT__
429 #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit"
430 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields)
431 {
432   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
433   PetscErrorCode    ierr;
434   PC_FieldSplitLink ilink,next = jac->head;
435   char              prefix[128];
436   PetscInt          i;
437 
438   PetscFunctionBegin;
439   if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested");
440   for (i=0; i<n; i++) {
441     if (fields[i] >= jac->bs) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
442     if (fields[i] < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
443   }
444   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
445   ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields);CHKERRQ(ierr);
446   ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr);
447   ilink->nfields = n;
448   ilink->next    = PETSC_NULL;
449   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
450   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
451 
452   if (((PetscObject)pc)->prefix) {
453     sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
454   } else {
455     sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
456   }
457   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
458 
459   if (!next) {
460     jac->head       = ilink;
461     ilink->previous = PETSC_NULL;
462   } else {
463     while (next->next) {
464       next = next->next;
465     }
466     next->next      = ilink;
467     ilink->previous = next;
468   }
469   jac->nsplits++;
470   PetscFunctionReturn(0);
471 }
472 EXTERN_C_END
473 
474 
475 EXTERN_C_BEGIN
476 #undef __FUNCT__
477 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit"
478 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
479 {
480   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
481   PetscErrorCode    ierr;
482   PetscInt          cnt = 0;
483   PC_FieldSplitLink ilink = jac->head;
484 
485   PetscFunctionBegin;
486   ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr);
487   while (ilink) {
488     (*subksp)[cnt++] = ilink->ksp;
489     ilink = ilink->next;
490   }
491   if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits);
492   *n = jac->nsplits;
493   PetscFunctionReturn(0);
494 }
495 EXTERN_C_END
496 
497 EXTERN_C_BEGIN
498 #undef __FUNCT__
499 #define __FUNCT__ "PCFieldSplitSetIS_FieldSplit"
500 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS_FieldSplit(PC pc,IS is)
501 {
502   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
503   PetscErrorCode    ierr;
504     PC_FieldSplitLink ilink, next = jac->head;
505   char              prefix[128];
506 
507   PetscFunctionBegin;
508   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
509   ilink->next    = PETSC_NULL;
510   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
511   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
512 
513   if (((PetscObject)pc)->prefix) {
514     sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
515   } else {
516     sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
517   }
518   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
519 
520   if (!next) {
521     jac->head       = ilink;
522     ilink->previous = PETSC_NULL;
523   } else {
524     while (next->next) {
525       next = next->next;
526     }
527     next->next      = ilink;
528     ilink->previous = next;
529   }
530   jac->nsplits++;
531 
532   PetscFunctionReturn(0);
533 }
534 EXTERN_C_END
535 
536 #undef __FUNCT__
537 #define __FUNCT__ "PCFieldSplitSetFields"
538 /*@
539     PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
540 
541     Collective on PC
542 
543     Input Parameters:
544 +   pc  - the preconditioner context
545 .   n - the number of fields in this split
546 .   fields - the fields in this split
547 
548     Level: intermediate
549 
550 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
551 
552 @*/
553 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields)
554 {
555   PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *);
556 
557   PetscFunctionBegin;
558   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
559   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);CHKERRQ(ierr);
560   if (f) {
561     ierr = (*f)(pc,n,fields);CHKERRQ(ierr);
562   }
563   PetscFunctionReturn(0);
564 }
565 
566 #undef __FUNCT__
567 #define __FUNCT__ "PCFieldSplitSetIS"
568 /*@
569     PCFieldSplitSetIS - Sets the exact elements for field
570 
571     Collective on PC
572 
573     Input Parameters:
574 +   pc  - the preconditioner context
575 .   is - the index set that defines the vector elements in this field
576 
577     Level: intermediate
578 
579 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
580 
581 @*/
582 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS(PC pc,IS is)
583 {
584   PetscErrorCode ierr,(*f)(PC,IS);
585 
586   PetscFunctionBegin;
587   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
588   PetscValidHeaderSpecific(is,IS_COOKIE,1);
589   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetIS_C",(void (**)(void))&f);CHKERRQ(ierr);
590   if (f) {
591     ierr = (*f)(pc,is);CHKERRQ(ierr);
592   }
593   PetscFunctionReturn(0);
594 }
595 
596 #undef __FUNCT__
597 #define __FUNCT__ "PCFieldSplitSetBlockSize"
598 /*@
599     PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
600       fieldsplit preconditioner. If not set the matrix block size is used.
601 
602     Collective on PC
603 
604     Input Parameters:
605 +   pc  - the preconditioner context
606 -   bs - the block size
607 
608     Level: intermediate
609 
610 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
611 
612 @*/
613 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
614 {
615   PetscErrorCode ierr,(*f)(PC,PetscInt);
616 
617   PetscFunctionBegin;
618   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
619   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",(void (**)(void))&f);CHKERRQ(ierr);
620   if (f) {
621     ierr = (*f)(pc,bs);CHKERRQ(ierr);
622   }
623   PetscFunctionReturn(0);
624 }
625 
626 #undef __FUNCT__
627 #define __FUNCT__ "PCFieldSplitGetSubKSP"
628 /*@C
629    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
630 
631    Collective on KSP
632 
633    Input Parameter:
634 .  pc - the preconditioner context
635 
636    Output Parameters:
637 +  n - the number of split
638 -  pc - the array of KSP contexts
639 
640    Note:
641    After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed
642 
643    You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
644 
645    Level: advanced
646 
647 .seealso: PCFIELDSPLIT
648 @*/
649 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
650 {
651   PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **);
652 
653   PetscFunctionBegin;
654   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
655   PetscValidIntPointer(n,2);
656   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);CHKERRQ(ierr);
657   if (f) {
658     ierr = (*f)(pc,n,subksp);CHKERRQ(ierr);
659   } else {
660     SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC");
661   }
662   PetscFunctionReturn(0);
663 }
664 
665 EXTERN_C_BEGIN
666 #undef __FUNCT__
667 #define __FUNCT__ "PCFieldSplitSetType_FieldSplit"
668 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
669 {
670   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
671 
672   PetscFunctionBegin;
673   jac->type = type;
674   PetscFunctionReturn(0);
675 }
676 EXTERN_C_END
677 
678 EXTERN_C_BEGIN
679 #undef __FUNCT__
680 #define __FUNCT__ "PCFieldSplitSetBlockSize_FieldSplit"
681 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
682 {
683   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
684 
685   PetscFunctionBegin;
686   if (bs < 1) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
687   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);
688   jac->bs = bs;
689   PetscFunctionReturn(0);
690 }
691 EXTERN_C_END
692 
693 #undef __FUNCT__
694 #define __FUNCT__ "PCFieldSplitSetType"
695 /*@
696    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
697 
698    Collective on PC
699 
700    Input Parameter:
701 .  pc - the preconditioner context
702 .  type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE
703 
704    Options Database Key:
705 .  -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets fieldsplit preconditioner type
706 
707    Level: Developer
708 
709 .keywords: PC, set, type, composite preconditioner, additive, multiplicative
710 
711 .seealso: PCCompositeSetType()
712 
713 @*/
714 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType(PC pc,PCCompositeType type)
715 {
716   PetscErrorCode ierr,(*f)(PC,PCCompositeType);
717 
718   PetscFunctionBegin;
719   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
720   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);CHKERRQ(ierr);
721   if (f) {
722     ierr = (*f)(pc,type);CHKERRQ(ierr);
723   }
724   PetscFunctionReturn(0);
725 }
726 
727 /* -------------------------------------------------------------------------------------*/
728 /*MC
729    PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
730                   fields or groups of fields
731 
732 
733      To set options on the solvers for each block append -sub_ to all the PC
734         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1
735 
736      To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
737          and set the options directly on the resulting KSP object
738 
739    Level: intermediate
740 
741    Options Database Keys:
742 +   -pc_splitfield_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
743 .   -pc_splitfield_default - automatically add any fields to additional splits that have not
744                               been supplied explicitly by -pc_splitfield_%d_fields
745 .   -pc_splitfield_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
746 -   -pc_splitfield_type <additive,multiplicative>
747 
748    Concepts: physics based preconditioners
749 
750 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
751            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(),PCFieldSplitSetType()
752 M*/
753 
754 EXTERN_C_BEGIN
755 #undef __FUNCT__
756 #define __FUNCT__ "PCCreate_FieldSplit"
757 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_FieldSplit(PC pc)
758 {
759   PetscErrorCode ierr;
760   PC_FieldSplit  *jac;
761 
762   PetscFunctionBegin;
763   ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr);
764   jac->bs        = -1;
765   jac->nsplits   = 0;
766   jac->type      = PC_COMPOSITE_ADDITIVE;
767 
768   pc->data     = (void*)jac;
769 
770   pc->ops->apply             = PCApply_FieldSplit;
771   pc->ops->applytranspose    = PCApplyTranspose_FieldSplit;
772   pc->ops->setup             = PCSetUp_FieldSplit;
773   pc->ops->destroy           = PCDestroy_FieldSplit;
774   pc->ops->setfromoptions    = PCSetFromOptions_FieldSplit;
775   pc->ops->view              = PCView_FieldSplit;
776   pc->ops->applyrichardson   = 0;
777 
778   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
779                     PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
780   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
781                     PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr);
782   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
783                     PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr);
784   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
785                     PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr);
786   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
787                     PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr);
788   PetscFunctionReturn(0);
789 }
790 EXTERN_C_END
791 
792 
793