xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision 8bc8193efbc389280f83b3d41dffa9e2d23e2ace) !
1 /*
2 
3 */
4 #include "src/ksp/pc/pcimpl.h"     /*I "petscpc.h" I*/
5 
6 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
7 struct _PC_FieldSplitLink {
8   KSP               ksp;
9   Vec               x,y;
10   PetscInt          nfields;
11   PetscInt          *fields;
12   VecScatter        sctx;
13   PC_FieldSplitLink next;
14 };
15 
16 typedef struct {
17   PCCompositeType   type;              /* additive or multiplicative */
18   PetscTruth        defaultsplit;
19   PetscInt          bs;
20   PetscInt          nsplits;
21   Vec               *x,*y,w1,w2;
22   Mat               *pmat;
23   IS                *is;
24   PC_FieldSplitLink head;
25 } PC_FieldSplit;
26 
27 #undef __FUNCT__
28 #define __FUNCT__ "PCView_FieldSplit"
29 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
30 {
31   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
32   PetscErrorCode    ierr;
33   PetscTruth        iascii;
34   PetscInt          i,j;
35   PC_FieldSplitLink link = jac->head;
36   const char        *types[] = {"additive","multiplicative"};
37 
38   PetscFunctionBegin;
39   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
40   if (iascii) {
41     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D",types[jac->type],jac->nsplits);CHKERRQ(ierr);
42     ierr = PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr);
43     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
44     for (i=0; i<jac->nsplits; i++) {
45       ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
46       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
47       for (j=0; j<link->nfields; j++) {
48         if (j > 0) {
49           ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
50         }
51         ierr = PetscViewerASCIIPrintf(viewer," %D",link->fields[j]);CHKERRQ(ierr);
52       }
53       ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
54       ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
55       ierr = KSPView(link->ksp,viewer);CHKERRQ(ierr);
56       link = link->next;
57     }
58     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
59   } else {
60     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
61   }
62   PetscFunctionReturn(0);
63 }
64 
65 #undef __FUNCT__
66 #define __FUNCT__ "PCFieldSplitSetDefaults"
67 static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
68 {
69   PC_FieldSplit     *jac  = (PC_FieldSplit*)pc->data;
70   PetscErrorCode    ierr;
71   PC_FieldSplitLink link = jac->head;
72   PetscInt          i;
73   PetscTruth        flg = PETSC_FALSE,*fields;
74 
75   PetscFunctionBegin;
76   ierr = PetscOptionsGetLogical(pc->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr);
77   if (!link || flg) {
78     ierr = PetscLogInfo(pc,"PCFieldSplitSetDefaults: Using default splitting of fields");CHKERRQ(ierr);
79     if (jac->bs <= 0) {
80       ierr   = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr);
81     }
82     ierr = PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);CHKERRQ(ierr);
83     ierr = PetscMemzero(fields,jac->bs*sizeof(PetscTruth));CHKERRQ(ierr);
84     while (link) {
85       for (i=0; i<link->nfields; i++) {
86         fields[link->fields[i]] = PETSC_TRUE;
87       }
88       link = link->next;
89     }
90     jac->defaultsplit = PETSC_TRUE;
91     for (i=0; i<jac->bs; i++) {
92       if (!fields[i]) {
93 	ierr = PCFieldSplitSetFields(pc,1,&i);CHKERRQ(ierr);
94       } else {
95         jac->defaultsplit = PETSC_FALSE;
96       }
97     }
98   }
99   PetscFunctionReturn(0);
100 }
101 
102 
103 #undef __FUNCT__
104 #define __FUNCT__ "PCSetUp_FieldSplit"
105 static PetscErrorCode PCSetUp_FieldSplit(PC pc)
106 {
107   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
108   PetscErrorCode    ierr;
109   PC_FieldSplitLink link;
110   PetscInt          i,nsplit;
111   MatStructure      flag = pc->flag;
112 
113   PetscFunctionBegin;
114   ierr   = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr);
115   nsplit = jac->nsplits;
116   link   = jac->head;
117 
118   /* get the matrices for each split */
119   if (!jac->is) {
120     PetscInt rstart,rend,nslots,bs;
121 
122     ierr   = MatGetBlockSize(pc->pmat,&bs);CHKERRQ(ierr);
123     ierr   = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr);
124     nslots = (rend - rstart)/bs;
125     ierr   = PetscMalloc(nsplit*sizeof(IS),&jac->is);CHKERRQ(ierr);
126     for (i=0; i<nsplit; i++) {
127       if (jac->defaultsplit) {
128 	ierr = ISCreateStride(pc->comm,nslots,rstart+i,nsplit,&jac->is[i]);CHKERRQ(ierr);
129       } else {
130         PetscInt   *ii,j,k,nfields = link->nfields,*fields = link->fields;
131         PetscTruth sorted;
132         ierr = PetscMalloc(link->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr);
133         for (j=0; j<nslots; j++) {
134           for (k=0; k<nfields; k++) {
135             ii[nfields*j + k] = rstart + bs*j + fields[k];
136           }
137         }
138 	ierr = ISCreateGeneral(pc->comm,nslots*nfields,ii,&jac->is[i]);CHKERRQ(ierr);
139         ierr = ISSorted(jac->is[i],&sorted);CHKERRQ(ierr);
140         if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split");
141         ierr = PetscFree(ii);CHKERRQ(ierr);
142         link = link->next;
143       }
144     }
145   }
146 
147   if (!jac->pmat) {
148     ierr = MatGetSubMatrices(pc->pmat,nsplit,jac->is,jac->is,MAT_INITIAL_MATRIX,&jac->pmat);CHKERRQ(ierr);
149   } else {
150     ierr = MatGetSubMatrices(pc->pmat,nsplit,jac->is,jac->is,MAT_REUSE_MATRIX,&jac->pmat);CHKERRQ(ierr);
151   }
152 
153   /* set up the individual PCs */
154   i    = 0;
155   link = jac->head;
156   while (link) {
157     ierr = KSPSetOperators(link->ksp,jac->pmat[i],jac->pmat[i],flag);CHKERRQ(ierr);
158     ierr = KSPSetFromOptions(link->ksp);CHKERRQ(ierr);
159     ierr = KSPSetUp(link->ksp);CHKERRQ(ierr);
160     i++;
161     link = link->next;
162   }
163 
164   /* create work vectors for each split */
165   if (!jac->x) {
166     Vec xtmp;
167     ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr);
168     link = jac->head;
169     for (i=0; i<nsplit; i++) {
170       Mat A;
171       ierr      = KSPGetOperators(link->ksp,PETSC_NULL,&A,PETSC_NULL);CHKERRQ(ierr);
172       ierr      = MatGetVecs(A,&link->x,&link->y);CHKERRQ(ierr);
173       jac->x[i] = link->x;
174       jac->y[i] = link->y;
175       link      = link->next;
176     }
177     /* compute scatter contexts needed by multiplicative versions and non-default splits */
178 
179     link = jac->head;
180     ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr);
181     for (i=0; i<nsplit; i++) {
182       ierr = VecScatterCreate(xtmp,jac->is[i],jac->x[i],PETSC_NULL,&link->sctx);CHKERRQ(ierr);
183       link = link->next;
184     }
185     ierr = VecDestroy(xtmp);CHKERRQ(ierr);
186   }
187   PetscFunctionReturn(0);
188 }
189 
190 #define FieldSplitSplitSolveAdd(link,xx,yy) \
191     (VecScatterBegin(xx,link->x,INSERT_VALUES,SCATTER_FORWARD,link->sctx) || \
192      VecScatterEnd(xx,link->x,INSERT_VALUES,SCATTER_FORWARD,link->sctx) || \
193      KSPSolve(link->ksp,link->x,link->y) || \
194      VecScatterBegin(link->y,yy,ADD_VALUES,SCATTER_REVERSE,link->sctx) || \
195      VecScatterEnd(link->y,yy,ADD_VALUES,SCATTER_REVERSE,link->sctx))
196 
197 #undef __FUNCT__
198 #define __FUNCT__ "PCApply_FieldSplit"
199 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
200 {
201   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
202   PetscErrorCode    ierr;
203   PC_FieldSplitLink link = jac->head;
204   PetscScalar       zero = 0.0,mone = -1.0;
205 
206   PetscFunctionBegin;
207   if (jac->type == PC_COMPOSITE_ADDITIVE) {
208     if (jac->defaultsplit) {
209       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
210       while (link) {
211 	ierr = KSPSolve(link->ksp,link->x,link->y);CHKERRQ(ierr);
212 	link = link->next;
213       }
214       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
215     } else {
216       PetscInt    i = 0;
217 
218       ierr = VecSet(&zero,y);CHKERRQ(ierr);
219       while (link) {
220         ierr = FieldSplitSplitSolveAdd(link,x,y);CHKERRQ(ierr);
221 	link = link->next;
222 	i++;
223       }
224     }
225   } else {
226     if (!jac->w1) {
227       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
228       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
229     }
230     ierr = VecSet(&zero,y);CHKERRQ(ierr);
231     ierr = FieldSplitSplitSolveAdd(link,x,y);CHKERRQ(ierr);
232     while (link->next) {
233       link = link->next;
234       ierr = MatMult(pc->pmat,y,jac->w1);CHKERRQ(ierr);
235       ierr = VecWAXPY(&mone,jac->w1,x,jac->w2);CHKERRQ(ierr);
236       ierr = FieldSplitSplitSolveAdd(link,jac->w2,y);CHKERRQ(ierr);
237     }
238   }
239   PetscFunctionReturn(0);
240 }
241 
242 #undef __FUNCT__
243 #define __FUNCT__ "PCDestroy_FieldSplit"
244 static PetscErrorCode PCDestroy_FieldSplit(PC pc)
245 {
246   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
247   PetscErrorCode    ierr;
248   PC_FieldSplitLink link = jac->head,next;
249 
250   PetscFunctionBegin;
251   while (link) {
252     ierr = KSPDestroy(link->ksp);CHKERRQ(ierr);
253     if (link->x) {ierr = VecDestroy(link->x);CHKERRQ(ierr);}
254     if (link->y) {ierr = VecDestroy(link->y);CHKERRQ(ierr);}
255     if (link->sctx) {ierr = VecScatterDestroy(link->sctx);CHKERRQ(ierr);}
256     next = link->next;
257     ierr = PetscFree2(link,link->fields);CHKERRQ(ierr);
258     link = next;
259   }
260   if (jac->x) {ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr);}
261   if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);}
262   if (jac->is) {
263     PetscInt i;
264     for (i=0; i<jac->nsplits; i++) {ierr = ISDestroy(jac->is[i]);CHKERRQ(ierr);}
265     ierr = PetscFree(jac->is);CHKERRQ(ierr);
266   }
267   if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);}
268   if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);}
269   ierr = PetscFree(jac);CHKERRQ(ierr);
270   PetscFunctionReturn(0);
271 }
272 
273 #undef __FUNCT__
274 #define __FUNCT__ "PCSetFromOptions_FieldSplit"
275 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
276 /*   This does not call KSPSetFromOptions() on the subksp's, see PCSetFromOptionsBJacobi/ASM() */
277 {
278   PetscErrorCode ierr;
279   PetscInt       i = 0,nfields,fields[12],indx;
280   PetscTruth     flg;
281   char           optionname[128];
282   const char     *types[] = {"additive","multiplicative"};
283 
284   PetscFunctionBegin;
285   ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr);
286   ierr = PetscOptionsEList("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",types,2,types[0],&indx,&flg);CHKERRQ(ierr);
287   if (flg) {
288     ierr = PCFieldSplitSetType(pc,(PCCompositeType)indx);CHKERRQ(ierr);
289   }
290   while (PETSC_TRUE) {
291     sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
292     nfields = 12;
293     ierr    = PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);CHKERRQ(ierr);
294     if (!flg) break;
295     if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
296     ierr = PCFieldSplitSetFields(pc,nfields,fields);CHKERRQ(ierr);
297   }
298   ierr = PetscOptionsTail();CHKERRQ(ierr);
299   PetscFunctionReturn(0);
300 }
301 
302 /*------------------------------------------------------------------------------------*/
303 
304 EXTERN_C_BEGIN
305 #undef __FUNCT__
306 #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit"
307 PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields)
308 {
309   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
310   PetscErrorCode    ierr;
311   PC_FieldSplitLink link,next = jac->head;
312   char              prefix[128];
313 
314   PetscFunctionBegin;
315   if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested");
316   ierr = PetscMalloc2(1,struct _PC_FieldSplitLink,&link,n,PetscInt,&link->fields);CHKERRQ(ierr);
317   ierr = PetscMemcpy(link->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr);
318   link->nfields = n;
319   link->next    = PETSC_NULL;
320   ierr          = KSPCreate(pc->comm,&link->ksp);CHKERRQ(ierr);
321   ierr          = KSPSetType(link->ksp,KSPPREONLY);CHKERRQ(ierr);
322 
323   if (pc->prefix) {
324     sprintf(prefix,"%sfieldsplit_%d_",pc->prefix,(int)jac->nsplits);
325   } else {
326     sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
327   }
328   ierr = KSPSetOptionsPrefix(link->ksp,prefix);CHKERRQ(ierr);
329 
330   if (!next) {
331     jac->head = link;
332   } else {
333     while (next->next) {
334       next = next->next;
335     }
336     next->next = link;
337   }
338   jac->nsplits++;
339   PetscFunctionReturn(0);
340 }
341 EXTERN_C_END
342 
343 
344 EXTERN_C_BEGIN
345 #undef __FUNCT__
346 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit"
347 PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
348 {
349   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
350   PetscErrorCode    ierr;
351   PetscInt          cnt = 0;
352   PC_FieldSplitLink link = jac->head;
353 
354   PetscFunctionBegin;
355   ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr);
356   while (link) {
357     (*subksp)[cnt++] = link->ksp;
358     link = link->next;
359   }
360   if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits);
361   *n = jac->nsplits;
362   PetscFunctionReturn(0);
363 }
364 EXTERN_C_END
365 
366 #undef __FUNCT__
367 #define __FUNCT__ "PCFieldSplitSetFields"
368 /*@
369     PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
370 
371     Collective on PC
372 
373     Input Parameters:
374 +   pc  - the preconditioner context
375 .   n - the number of fields in this split
376 .   fields - the fields in this split
377 
378     Level: intermediate
379 
380 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT
381 
382 @*/
383 PetscErrorCode PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields)
384 {
385   PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *);
386 
387   PetscFunctionBegin;
388   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
389   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);CHKERRQ(ierr);
390   if (f) {
391     ierr = (*f)(pc,n,fields);CHKERRQ(ierr);
392   }
393   PetscFunctionReturn(0);
394 }
395 
396 #undef __FUNCT__
397 #define __FUNCT__ "PCFieldSplitGetSubKSP"
398 /*@C
399    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
400 
401    Collective on KSP
402 
403    Input Parameter:
404 .  pc - the preconditioner context
405 
406    Output Parameters:
407 +  n - the number of split
408 -  pc - the array of KSP contexts
409 
410    Note:
411    After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed
412 
413    You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
414 
415    Level: advanced
416 
417 .seealso: PCFIELDSPLIT
418 @*/
419 PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
420 {
421   PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **);
422 
423   PetscFunctionBegin;
424   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
425   PetscValidIntPointer(n,2);
426   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);CHKERRQ(ierr);
427   if (f) {
428     ierr = (*f)(pc,n,subksp);CHKERRQ(ierr);
429   } else {
430     SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC");
431   }
432   PetscFunctionReturn(0);
433 }
434 
435 EXTERN_C_BEGIN
436 #undef __FUNCT__
437 #define __FUNCT__ "PCFieldSplitSetType_FieldSplit"
438 PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
439 {
440   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
441 
442   PetscFunctionBegin;
443   jac->type = type;
444   PetscFunctionReturn(0);
445 }
446 EXTERN_C_END
447 
448 #undef __FUNCT__
449 #define __FUNCT__ "PCFieldSplitSetType"
450 /*@C
451    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
452 
453    Collective on PC
454 
455    Input Parameter:
456 .  pc - the preconditioner context
457 .  type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE
458 
459    Options Database Key:
460 .  -pc_fieldsplit_type <type: one of multiplicative, additive, special> - Sets fieldsplit preconditioner type
461 
462    Level: Developer
463 
464 .keywords: PC, set, type, composite preconditioner, additive, multiplicative
465 
466 .seealso: PCCompositeSetType()
467 
468 @*/
469 PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type)
470 {
471   PetscErrorCode ierr,(*f)(PC,PCCompositeType);
472 
473   PetscFunctionBegin;
474   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
475   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);CHKERRQ(ierr);
476   if (f) {
477     ierr = (*f)(pc,type);CHKERRQ(ierr);
478   }
479   PetscFunctionReturn(0);
480 }
481 
482 /* -------------------------------------------------------------------------------------*/
483 /*MC
484    PCFieldSplit - Preconditioner created by combining seperate preconditioners for individual
485                   fields or groups of fields
486 
487 
488      To set options on the solvers for each block append -sub_ to all the PC
489         options database keys. For example, -sub_pc_type ilu -sub_pc_ilu_levels 1
490 
491      To set the options on the solvers seperate for each block call PCFieldSplitGetSubKSP()
492          and set the options directly on the resulting KSP object
493 
494    Level: intermediate
495 
496    Options Database Keys:
497 +   -pc_splitfield_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
498 .   -pc_splitfield_default - automatically add any fields to additional splits that have not
499                               been supplied explicitly by -pc_splitfield_%d_fields
500 -   -pc_splitfield_type <additive,multiplicative>
501 
502    Concepts: physics based preconditioners
503 
504 .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
505            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields()
506 M*/
507 
508 EXTERN_C_BEGIN
509 #undef __FUNCT__
510 #define __FUNCT__ "PCCreate_FieldSplit"
511 PetscErrorCode PCCreate_FieldSplit(PC pc)
512 {
513   PetscErrorCode ierr;
514   PC_FieldSplit  *jac;
515 
516   PetscFunctionBegin;
517   ierr = PetscNew(PC_FieldSplit,&jac);CHKERRQ(ierr);
518   PetscLogObjectMemory(pc,sizeof(PC_FieldSplit));
519   ierr = PetscMemzero(jac,sizeof(PC_FieldSplit));CHKERRQ(ierr);
520   jac->bs      = -1;
521   jac->nsplits = 0;
522   jac->type    = PC_COMPOSITE_ADDITIVE;
523   pc->data     = (void*)jac;
524 
525   pc->ops->apply             = PCApply_FieldSplit;
526   pc->ops->setup             = PCSetUp_FieldSplit;
527   pc->ops->destroy           = PCDestroy_FieldSplit;
528   pc->ops->setfromoptions    = PCSetFromOptions_FieldSplit;
529   pc->ops->view              = PCView_FieldSplit;
530   pc->ops->applyrichardson   = 0;
531 
532   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
533                     PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
534   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
535                     PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr);
536   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
537                     PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr);
538   PetscFunctionReturn(0);
539 }
540 EXTERN_C_END
541 
542 
543