xref: /petsc/src/snes/impls/multiblock/multiblock.c (revision c7543cce9782156fbe88d1c70af3ea00db4c16aa)
1 #include <private/snesimpl.h>
2 
3 typedef struct _BlockDesc *BlockDesc;
4 struct _BlockDesc {
5   char        *name;    /* Block name */
6   PetscInt     nfields; /* If block is defined on a DA, the number of DA fields */
7   PetscInt    *fields;  /* If block is defined on a DA, the list of DA fields */
8   IS           is;      /* Index sets defining the block */
9   VecScatter   sctx;    /* Scatter mapping global Vec to blockVec */
10   SNES         snes;    /* Solver for this block */
11   Vec          x;
12   BlockDesc    next, previous;
13 };
14 
15 typedef struct {
16   PetscBool       issetup;       /* Flag is true after the all ISs and operators have been defined */
17   PetscBool       defined;       /* Flag is true after the blocks have been defined, to prevent more blocks from being added */
18   PetscBool       defaultblocks; /* Flag is true for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
19   PetscInt        numBlocks;     /* Number of blocks (can be fields, domains, etc.) */
20   PetscInt        bs;            /* Block size for IS, Vec and Mat structures */
21   PCCompositeType type;          /* Solver combination method (additive, multiplicative, etc.) */
22   BlockDesc       blocks;        /* Linked list of block descriptors */
23 } SNES_Multiblock;
24 
25 #undef __FUNCT__
26 #define __FUNCT__ "SNESReset_Multiblock"
27 PetscErrorCode SNESReset_Multiblock(SNES snes)
28 {
29   SNES_Multiblock *mb     = (SNES_Multiblock *) snes->data;
30   BlockDesc        blocks = mb->blocks, next;
31   PetscErrorCode   ierr;
32 
33   PetscFunctionBegin;
34   while (blocks) {
35     ierr = SNESReset(blocks->snes);CHKERRQ(ierr);
36     //ierr = VecDestroy(&blocks->x);CHKERRQ(ierr);
37     //ierr = VecDestroy(&blocks->y);CHKERRQ(ierr);
38     ierr = VecScatterDestroy(&blocks->sctx);CHKERRQ(ierr);
39     ierr = ISDestroy(&blocks->is);CHKERRQ(ierr);
40     next   = blocks->next;
41     blocks = next;
42   }
43   if (snes->work) {ierr = VecDestroyVecs(snes->nwork, &snes->work);CHKERRQ(ierr);}
44   PetscFunctionReturn(0);
45 }
46 
47 /*
48   SNESDestroy_Multiblock - Destroys the private SNES_Multiblock context that was created with SNESCreate_Multiblock().
49 
50   Input Parameter:
51 . snes - the SNES context
52 
53   Application Interface Routine: SNESDestroy()
54 */
55 #undef __FUNCT__
56 #define __FUNCT__ "SNESDestroy_Multiblock"
57 PetscErrorCode SNESDestroy_Multiblock(SNES snes)
58 {
59   SNES_Multiblock *mb     = (SNES_Multiblock *) snes->data;
60   BlockDesc        blocks = mb->blocks, next;
61   PetscErrorCode   ierr;
62 
63   PetscFunctionBegin;
64   ierr = SNESReset_Multiblock(snes);CHKERRQ(ierr);
65   while (blocks) {
66     next = blocks->next;
67     ierr = SNESDestroy(&blocks->snes);CHKERRQ(ierr);
68     ierr = PetscFree(blocks->name);CHKERRQ(ierr);
69     ierr = PetscFree(blocks->fields);CHKERRQ(ierr);
70     ierr = PetscFree(blocks);CHKERRQ(ierr);
71     blocks = next;
72   }
73   ierr = PetscFree(snes->data);CHKERRQ(ierr);
74   PetscFunctionReturn(0);
75 }
76 
77 #undef __FUNCT__
78 #define __FUNCT__ "SNESMultiblockSetFieldsRuntime_Private"
79 /* Precondition: blocksize is set to a meaningful value */
80 static PetscErrorCode SNESMultiblockSetFieldsRuntime_Private(PC pc)
81 {
82   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
83   PetscInt        *ifields;
84   PetscInt         i, nfields;
85   PetscBool        flg = PETSC_TRUE;
86   char             optionname[128], name[8];
87   PetscErrorCode   ierr;
88 
89   PetscFunctionBegin;
90   ierr = PetscMalloc(mb->bs * sizeof(PetscInt), &ifields);CHKERRQ(ierr);
91   for(i = 0; ; ++i) {
92     ierr = PetscSNPrintf(name, sizeof name, "%D", i);CHKERRQ(ierr);
93     ierr = PetscSNPrintf(optionname, sizeof optionname, "-snes_multiblock_%D_fields", i);CHKERRQ(ierr);
94     nfields = mb->bs;
95     ierr    = PetscOptionsGetIntArray(((PetscObject) snes)->prefix, optionname, ifields, &nfields, &flg);CHKERRQ(ierr);
96     if (!flg) break;
97     if (!nfields) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields");
98     ierr = SNESMultiblockSetFields(pc, name, nfields, ifields);CHKERRQ(ierr);
99   }
100   if (i > 0) {
101     /* Makes command-line setting of blocks take precedence over setting them in code.
102        Otherwise subsequent calls to SNESMultiblockSetIS() or SNESMultiblockSetFields() would
103        create new blocks, which would probably not be what the user wanted. */
104     mb->defined = PETSC_TRUE;
105   }
106   ierr = PetscFree(ifields);CHKERRQ(ierr);
107   PetscFunctionReturn(0);
108 }
109 
110 #undef __FUNCT__
111 #define __FUNCT__ "SNESMultiblockSetDefaults"
112 static PetscErrorCode SNESMultiblockSetDefaults(SNES snes)
113 {
114   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
115   BlockDesc        blocks = mb->blocks;
116   PetscInt         i;
117   PetscErrorCode   ierr;
118 
119   PetscFunctionBegin;
120   if (!blocks) {
121     if (snes->dm) {
122       PetscBool dmcomposite;
123 
124       ierr = PetscTypeCompare((PetscObject) snes->dm, DMCOMPOSITE, &dmcomposite);CHKERRQ(ierr);
125       if (dmcomposite) {
126         PetscInt nDM;
127         IS      *fields;
128 
129         ierr = PetscInfo(pc,"Setting up physics based multiblock solver using the embedded DM\n");CHKERRQ(ierr);
130         ierr = DMCompositeGetNumberDM(snes->dm, &nDM);CHKERRQ(ierr);
131         ierr = DMCompositeGetGlobalISs(snes->dm, &fields);CHKERRQ(ierr);
132         for(i = 0; i < nDM; ++i) {
133           char name[8];
134 
135           ierr = PetscSNPrintf(name, sizeof name, "%D", i);CHKERRQ(ierr);
136           ierr = SNESMultiblockSetIS(snes, name, fields[i]);CHKERRQ(ierr);
137           ierr = ISDestroy(&fields[i]);CHKERRQ(ierr);
138         }
139         ierr = PetscFree(fields);CHKERRQ(ierr);
140       }
141     } else {
142       PetscBool flg    = PETSC_FALSE;
143       PetscBool stokes = PETSC_FALSE;
144 
145       if (mb->bs <= 0) {
146         if (snes->jac) {
147           ierr = MatGetBlockSize(snes->jac, &mb->bs);CHKERRQ(ierr);
148         } else {
149           mb->bs = 1;
150         }
151       }
152 
153       ierr = PetscOptionsGetBool(((PetscObject) snes)->prefix, "-snes_multiblock_default", &flg, PETSC_NULL);CHKERRQ(ierr);
154       ierr = PetscOptionsGetBool(((PetscObject) snes)->prefix, "-snes_multiblock_detect_saddle_point", &stokes, PETSC_NULL);CHKERRQ(ierr);
155       if (stokes) {
156         IS       zerodiags, rest;
157         PetscInt nmin, nmax;
158 
159         ierr = MatGetOwnershipRange(snes->jac, &nmin, &nmax);CHKERRQ(ierr);
160         ierr = MatFindZeroDiagonals(snes->jac, &zerodiags);CHKERRQ(ierr);
161         ierr = ISComplement(zerodiags, nmin, nmax, &rest);CHKERRQ(ierr);
162         ierr = SNESMultiblockSetIS(snes, "0", rest);CHKERRQ(ierr);
163         ierr = SNESMultiblockSetIS(snes, "1", zerodiags);CHKERRQ(ierr);
164         ierr = ISDestroy(&zerodiags);CHKERRQ(ierr);
165         ierr = ISDestroy(&rest);CHKERRQ(ierr);
166       } else {
167         if (!flg) {
168           /* Allow user to set fields from command line, if bs was known at the time of SNESSetFromOptions_Multiblock()
169            then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
170           ierr = SNESMultiblockSetFieldsRuntime_Private(pc);CHKERRQ(ierr);
171           if (mb->defined) {ierr = PetscInfo(snes, "Blocks defined using the options database\n");CHKERRQ(ierr);}
172         }
173         if (flg || !mb->defined) {
174           ierr = PetscInfo(snes, "Using default splitting of fields\n");CHKERRQ(ierr);
175           for(i = 0; i < mb->bs; ++i) {
176             char name[8];
177 
178             ierr = PetscSNPrintf(name, sizeof name, "%D", i);CHKERRQ(ierr);
179             ierr = SNESMultiblockSetFields(snes, name, 1, &i);CHKERRQ(ierr);
180           }
181           mb->defaultblocks = PETSC_TRUE;
182         }
183       }
184     }
185   } else if (mb->numBlocks == 1) {
186     if (blocks->is) {
187       IS       is2;
188       PetscInt nmin, nmax;
189 
190       ierr = MatGetOwnershipRange(snes->jac, &nmin, &nmax);CHKERRQ(ierr);
191       ierr = ISComplement(blocks->is, nmin, nmax, &is2);CHKERRQ(ierr);
192       ierr = SNESMultiblockSetIS(snes, "1", is2);CHKERRQ(ierr);
193       ierr = ISDestroy(&is2);CHKERRQ(ierr);
194     } else {
195       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least two sets of fields to SNES multiblock");
196     }
197   }
198   if (mb->numBlocks < 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unhandled case, must have at least two blocks");
199   PetscFunctionReturn(0);
200 }
201 
202 /*
203    SNESSetUp_Multiblock - Sets up the internal data structures for the later use
204    of the SNESMULTIBLOCK nonlinear solver.
205 
206    Input Parameters:
207 +  snes - the SNES context
208 -  x - the solution vector
209 
210    Application Interface Routine: SNESSetUp()
211 */
212 #undef __FUNCT__
213 #define __FUNCT__ "SNESSetUp_Multiblock"
214 PetscErrorCode SNESSetUp_Multiblock(SNES snes)
215 {
216   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
217   BlockDesc        blocks;
218   PetscInt         i, numBlocks;
219   PetscErrorCode   ierr;
220 
221   PetscFunctionBegin;
222   /* ierr = SNESDefaultGetWork(snes, 1);CHKERRQ(ierr); */
223   ierr = PCFieldSplitSetDefaults(snes);CHKERRQ(ierr);
224   numBlocks = mb->numBlocks;
225   blocks    = jac->head;
226 
227   /* Create ISs */
228   if (!mb->issetup) {
229     PetscInt  ccsize, rstart, rend, nslots, bs;
230     PetscBool sorted;
231 
232     mb->issetup = PETSC_TRUE;
233     bs     = mb->bs;
234     ierr   = MatGetOwnershipRange(snes->jac, &rstart, &rend);CHKERRQ(ierr);
235     ierr   = MatGetLocalSize(snes->jac, PETSC_NULL, &ccsize);CHKERRQ(ierr);
236     nslots = (rend - rstart)/bs;
237     for(i = 0; i < numBlocks; ++i) {
238       if (mb->defaultsplit) {
239         ierr = ISCreateStride(((PetscObject) snes)->comm, nslots, rstart+i, numBlocks, &blocks->is);CHKERRQ(ierr);
240       } else if (!blocks->is) {
241         if (blocks->nfields > 1) {
242           PetscInt *ii, j, k, nfields = blocks->nfields, *fields = blocks->fields;
243 
244           ierr = PetscMalloc(nfields*nslots*sizeof(PetscInt), &ii);CHKERRQ(ierr);
245           for(j = 0; j < nslots; ++j) {
246             for(k = 0; k < nfields; ++k) {
247               ii[nfields*j + k] = rstart + bs*j + fields[k];
248             }
249           }
250           ierr = ISCreateGeneral(((PetscObject) snes)->comm, nslots*nfields, ii, PETSC_OWN_POINTER, &blocks->is);CHKERRQ(ierr);
251         } else {
252           ierr = ISCreateStride(((PetscObject) snes)->comm, nslots, rstart+blocks->fields[0], bs, &blocks->is);CHKERRQ(ierr);
253         }
254       }
255       ierr = ISSorted(blocks->is, &sorted);CHKERRQ(ierr);
256       if (!sorted) {SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "Fields must be sorted when creating split");}
257       blocks = blocks->next;
258     }
259   }
260 
261 #if 0
262   /* Create matrices */
263   ilink  = jac->head;
264   if (!jac->pmat) {
265     ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr);
266     for (i=0; i<nsplit; i++) {
267       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
268       ilink = ilink->next;
269     }
270   } else {
271     for (i=0; i<nsplit; i++) {
272       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
273       ilink = ilink->next;
274     }
275   }
276   if (jac->realdiagonal) {
277     ilink = jac->head;
278     if (!jac->mat) {
279       ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->mat);CHKERRQ(ierr);
280       for (i=0; i<nsplit; i++) {
281         ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr);
282         ilink = ilink->next;
283       }
284     } else {
285       for (i=0; i<nsplit; i++) {
286         if (jac->mat[i]) {ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr);}
287         ilink = ilink->next;
288       }
289     }
290   } else {
291     jac->mat = jac->pmat;
292   }
293 #endif
294 
295 #if 0
296   if (jac->type != PC_COMPOSITE_ADDITIVE  && jac->type != PC_COMPOSITE_SCHUR) {
297     /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
298     ilink  = jac->head;
299     if (!jac->Afield) {
300       ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr);
301       for (i=0; i<nsplit; i++) {
302         ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
303         ilink = ilink->next;
304       }
305     } else {
306       for (i=0; i<nsplit; i++) {
307         ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
308         ilink = ilink->next;
309       }
310     }
311   }
312 #endif
313 
314   if (jac->type == PC_COMPOSITE_SCHUR) {
315 #if 0
316     IS       ccis;
317     PetscInt rstart,rend;
318     if (nsplit != 2) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
319 
320     /* When extracting off-diagonal submatrices, we take complements from this range */
321     ierr  = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr);
322 
323     /* need to handle case when one is resetting up the preconditioner */
324     if (jac->schur) {
325       ilink = jac->head;
326       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
327       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr);
328       ierr  = ISDestroy(&ccis);CHKERRQ(ierr);
329       ilink = ilink->next;
330       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
331       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr);
332       ierr  = ISDestroy(&ccis);CHKERRQ(ierr);
333       ierr  = MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);CHKERRQ(ierr);
334       ierr  = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);CHKERRQ(ierr);
335 
336      } else {
337       KSP ksp;
338       char schurprefix[256];
339 
340       /* extract the A01 and A10 matrices */
341       ilink = jac->head;
342       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
343       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr);
344       ierr  = ISDestroy(&ccis);CHKERRQ(ierr);
345       ilink = ilink->next;
346       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
347       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr);
348       ierr  = ISDestroy(&ccis);CHKERRQ(ierr);
349       /* Use mat[0] (diagonal block of the real matrix) preconditioned by pmat[0] */
350       ierr  = MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);CHKERRQ(ierr);
351       /* set tabbing and options prefix of KSP inside the MatSchur */
352       ierr  = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
353       ierr  = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);CHKERRQ(ierr);
354       ierr  = PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",jac->head->splitname);CHKERRQ(ierr);
355       ierr  = KSPSetOptionsPrefix(ksp,schurprefix);CHKERRQ(ierr);
356       ierr  = MatSetFromOptions(jac->schur);CHKERRQ(ierr);
357 
358       ierr  = KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);CHKERRQ(ierr);
359       ierr  = PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);CHKERRQ(ierr);
360       ierr  = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr);
361       ierr  = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
362       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
363         PC pc;
364         ierr = KSPGetPC(jac->kspschur,&pc);CHKERRQ(ierr);
365         ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr);
366         /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
367       }
368       ierr = PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);CHKERRQ(ierr);
369       ierr  = KSPSetOptionsPrefix(jac->kspschur,schurprefix);CHKERRQ(ierr);
370       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
371       ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr);
372 
373       ierr = PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);CHKERRQ(ierr);
374       ierr = MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);CHKERRQ(ierr);
375       ierr = MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);CHKERRQ(ierr);
376       ilink = jac->head;
377       ilink->x = jac->x[0]; ilink->y = jac->y[0];
378       ilink = ilink->next;
379       ilink->x = jac->x[1]; ilink->y = jac->y[1];
380     }
381 #endif
382   } else {
383     /* Set up the individual SNESs */
384     blocks = mb->blocks;
385     i      = 0;
386     while (blocks) {
387       ierr = KSPSetOperators(blocks->snes, jac->mat[i], jac->pmat[i], flag);CHKERRQ(ierr);
388       ierr = VecDuplicate(blocks->snes->vec_sol, &blocks->snes->x);CHKERRQ(ierr);
389       /* really want setfromoptions called in SNESSetFromOptions_Multiblock(), but it is not ready yet */
390       ierr = SNESSetFromOptions(blocks->snes);CHKERRQ(ierr);
391       ierr = SNESSetUp(blocks->snes);CHKERRQ(ierr);
392       blocks = blocks->next;
393       i++;
394     }
395   }
396 
397   /* Compute scatter contexts needed by multiplicative versions and non-default splits */
398   if (!mb->blocks->sctx) {
399     Vec xtmp;
400 
401     blocks = mb->blocks;
402     ierr = MatGetVecs(pc->pmat, &xtmp, PETSC_NULL);CHKERRQ(ierr);
403     while(blocks) {
404       ierr = VecScatterCreate(xtmp, blocks->is, blocks->x, PETSC_NULL, &blocks->sctx);CHKERRQ(ierr);
405       blocks = blocks->next;
406     }
407     ierr = VecDestroy(&xtmp);CHKERRQ(ierr);
408   }
409   PetscFunctionReturn(0);
410 }
411 
412 /*
413   SNESSetFromOptions_Multiblock - Sets various parameters for the SNESMULTIBLOCK method.
414 
415   Input Parameter:
416 . snes - the SNES context
417 
418   Application Interface Routine: SNESSetFromOptions()
419 */
420 #undef __FUNCT__
421 #define __FUNCT__ "SNESSetFromOptions_Multiblock"
422 static PetscErrorCode SNESSetFromOptions_Multiblock(SNES snes)
423 {
424   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
425   PCCompositeType  ctype;
426   PetscInt         bs;
427   PetscBool        flg;
428   PetscErrorCode   ierr;
429 
430   PetscFunctionBegin;
431   ierr = PetscOptionsHead("SNES Multiblock options");CHKERRQ(ierr);
432   ierr = PetscOptionsInt("-snes_multiblock_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", mb->bs, &bs, &flg);CHKERRQ(ierr);
433   if (flg) {ierr = PCFieldSplitSetBlockSize(snes, bs);CHKERRQ(ierr);}
434   ierr = PetscOptionsEnum("-snes_multiblock_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum) mb->type, (PetscEnum *) &ctype, &flg);CHKERRQ(ierr);
435   if (flg) {
436     ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr);
437   }
438   /* Only setup fields once */
439   if ((mb->bs > 0) && (mb->numBLocks == 0)) {
440     /* only allow user to set fields from command line if bs is already known, otherwise user can set them in SNESMultiblockSetDefaults() */
441     ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr);
442     if (mb->splitdefined) {ierr = PetscInfo(snes, "Splits defined using the options database\n");CHKERRQ(ierr);}
443   }
444   ierr = PetscOptionsTail();CHKERRQ(ierr);
445   PetscFunctionReturn(0);
446 }
447 
448 /*
449   SNESView_Multiblock - Prints info from the SNESMULTIBLOCK data structure.
450 
451   Input Parameters:
452 + SNES - the SNES context
453 - viewer - visualization context
454 
455   Application Interface Routine: SNESView()
456 */
457 #undef __FUNCT__
458 #define __FUNCT__ "SNESView_Multiblock"
459 static PetscErrorCode SNESView_Multiblock(SNES snes, PetscViewer viewer)
460 {
461   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
462   BlockDesc        blocks = mb->blocks;
463   PetscBool        iascii;
464   PetscErrorCode   ierr;
465 
466   PetscFunctionBegin;
467   ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
468   if (iascii) {
469     ierr = PetscViewerASCIIPrintf(viewer,"  Multiblock with %s composition: total blocks = %D, blocksize = %D\n", PCCompositeTypes[mb->type], mb->numBlocks, mb->bs);CHKERRQ(ierr);
470     ierr = PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following SNES objects:\n");CHKERRQ(ierr);
471     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
472     while (blocks) {
473       if (blocks->fields) {
474         PetscInt j;
475 
476 	ierr = PetscViewerASCIIPrintf(viewer, "Block %s Fields ", blocks->name);CHKERRQ(ierr);
477 	ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr);
478 	for(j = 0; j < blocks->nfields; ++j) {
479 	  if (j > 0) {
480 	    ierr = PetscViewerASCIIPrintf(viewer, ",");CHKERRQ(ierr);
481 	  }
482 	  ierr = PetscViewerASCIIPrintf(viewer, " %D", blocks->fields[j]);CHKERRQ(ierr);
483 	}
484 	ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
485         ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr);
486       } else {
487 	ierr = PetscViewerASCIIPrintf(viewer, "Block %s Defined by IS\n", blocks->names);CHKERRQ(ierr);
488       }
489       ierr = SNESView(blocks->snes, viewer);CHKERRQ(ierr);
490       blocks = blocks->next;
491     }
492     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
493   } else {
494     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP, "Viewer type %s not supported for SNES Multiblock", ((PetscObject)viewer)->type_name);
495   }
496   PetscFunctionReturn(0);
497 }
498 
499 /*
500   SNESSolve_Multiblock - Solves a nonlinear system with the Multiblock method.
501 
502   Input Parameters:
503 . snes - the SNES context
504 
505   Output Parameter:
506 . outits - number of iterations until termination
507 
508   Application Interface Routine: SNESSolve()
509 */
510 #undef __FUNCT__
511 #define __FUNCT__ "SNESSolve_Multiblock"
512 PetscErrorCode SNESSolve_Multiblock(SNES snes)
513 {
514   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
515   Vec              X, Y, F;
516   PetscReal        alpha = mb->alpha;
517   PetscReal        fnorm;
518   PetscInt         maxits, i;
519   PetscErrorCode   ierr;
520 
521   PetscFunctionBegin;
522   snes->reason = SNES_CONVERGED_ITERATING;
523 
524   maxits = snes->max_its;	 /* maximum number of iterations */
525   X      = snes->vec_sol;	 /* X^n */
526   Y      = snes->vec_sol_update; /* \tilde X */
527   F      = snes->vec_func;       /* residual vector */
528 
529   ierr = VecSetBlockSize(X, mb->bs);CHKERRQ(ierr);
530   ierr = VecSetBlockSize(Y, mb->bs);CHKERRQ(ierr);
531   ierr = VecSetBlockSize(F, mb->bs);CHKERRQ(ierr);
532   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
533   snes->iter = 0;
534   snes->norm = 0.;
535   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
536   ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
537   if (snes->domainerror) {
538     snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
539     PetscFunctionReturn(0);
540   }
541   ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F||  */
542   if (PetscIsInfOrNanReal(fnorm)) {SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in norm");}
543   ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
544   snes->norm = fnorm;
545   ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
546   SNESLogConvHistory(snes,fnorm,0);
547   ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
548 
549   /* set parameter for default relative tolerance convergence test */
550   snes->ttol = fnorm*snes->rtol;
551   /* test convergence */
552   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
553   if (snes->reason) PetscFunctionReturn(0);
554 
555   for(i = 0; i < maxits; i++) {
556     PetscBool  lsSuccess = PETSC_TRUE;
557 
558     /* Call general purpose update function */
559     if (snes->ops->update) {
560       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
561     }
562     /* Compute X^{new} from subsolves */
563     if (mb->type == PC_COMPOSITE_ADDITIVE) {
564       BlockDesc blocks = mb->blocks;
565 
566       if (mb->defaultsplit) {
567         ierr = VecStrideGatherAll(x, mb->x, INSERT_VALUES);CHKERRQ(ierr);
568         while (blocks) {
569           ierr = SNESSolve(blocks->snes, PETSC_NULL, blocks->x);CHKERRQ(ierr);
570           blocks = blocks->next;
571         }
572         ierr = VecStrideScatterAll(mb->y, y, INSERT_VALUES);CHKERRQ(ierr);
573       } else {
574         while (blocks) {
575           ierr = VecScatterBegin(blocks->sctx, X, blocks->x, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr);
576           ierr = VecScatterEnd(blocks->sctx, X, blocks->x, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr);
577           ierr = SNESSolve(blocks->snes, PETSC_NULL, blocks->x);CHKERRQ(ierr);
578           ierr = VecScatterBegin(blocks->sctx, blocks->x, X, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr);
579           ierr = VecScatterEnd(blocks->sctx, blocks->x, X, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr);
580           blocks = blocks->next;
581         }
582       }
583     } else {
584       SETERRQ1(((PetscObject) snes)->comm, PETSC_ERR_SUP, "Unsupported or unknown composition", (int) mb->type);
585     }
586     CHKMEMQ;
587     /* Compute F(X^{new}) */
588     ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr);
589     ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr);
590     if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated norm");
591 
592     if (snes->nfuncs >= snes->max_funcs) {
593       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
594       break;
595     }
596     if (snes->domainerror) {
597       snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN;
598       PetscFunctionReturn(0);
599     }
600     /* Monitor convergence */
601     ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr);
602     snes->iter = i+1;
603     snes->norm = fnorm;
604     ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr);
605     SNESLogConvHistory(snes,snes->norm,0);
606     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
607     /* Test for convergence */
608     ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
609     if (snes->reason) break;
610   }
611   if (i == maxits) {
612     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr);
613     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
614   }
615   PetscFunctionReturn(0);
616 }
617 
618 EXTERN_C_BEGIN
619 #undef __FUNCT__
620 #define __FUNCT__ "SNESMultiblockSetFields_Default"
621 PetscErrorCode SNESMultiblockSetFields_Default(SNES snes, const char name[], PetscInt n, const PetscInt fields[])
622 {
623   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
624   BlockDesc        newblock, next = mb->blocks;
625   char             prefix[128];
626   PetscInt         i;
627   PetscErrorCode   ierr;
628 
629   PetscFunctionBegin;
630   if (mb->defined) {
631     ierr = PetscInfo1(snes, "Ignoring new block \"%s\" because the blocks have already been defined\n", name);CHKERRQ(ierr);
632     PetscFunctionReturn(0);
633   }
634   for(i = 0; i < n; ++i) {
635     if (fields[i] >= mb->bs) {SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %D requested but only %D exist", fields[i], mb->bs);}
636     if (fields[i] < 0)       {SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %D requested", fields[i]);}
637   }
638   ierr = PetscNew(struct _BlockDesc, &newblock);CHKERRQ(ierr);
639   if (name) {
640     ierr = PetscStrallocpy(name, &newblock->name);CHKERRQ(ierr);
641   } else {
642     PetscInt len = floor(log10(mb->numBlocks))+1;
643 
644     ierr = PetscMalloc((len+1)*sizeof(char), &newblock->name);CHKERRQ(ierr);
645     ierr = PetscSNPrintf(newblock->name, len, "%s", mb->numBlocks);CHKERRQ(ierr);
646   }
647   newblock->nfields = n;
648   ierr = PetscMalloc(n*sizeof(PetscInt), &newblock->fields);CHKERRQ(ierr);
649   ierr = PetscMemcpy(newblock->fields, fields, n*sizeof(PetscInt));CHKERRQ(ierr);
650   newblock->next    = PETSC_NULL;
651   ierr = SNESCreate(((PetscObject) snes)->comm, &newblock->snes);CHKERRQ(ierr);
652   ierr = PetscObjectIncrementTabLevel((PetscObject) newblock->snes, (PetscObject) snes, 1);CHKERRQ(ierr);
653   ierr = SNESSetType(newblock->snes, SNESPICARD);CHKERRQ(ierr);
654   ierr = PetscLogObjectParent((PetscObject) snes, (PetscObject) newblock->snes);CHKERRQ(ierr);
655   ierr = PetscSNPrintf(prefix, sizeof prefix, "%smultiblock_%s_", ((PetscObject) snes)->prefix ? ((PetscObject) snes)->prefix : "", newblock->name);CHKERRQ(ierr);
656   ierr = SNESSetOptionsPrefix(newblock->snes, prefix);CHKERRQ(ierr);
657 
658   if (!next) {
659     mb->blocks         = newblock;
660     newblock->previous = PETSC_NULL;
661   } else {
662     while (next->next) {
663       next = next->next;
664     }
665     next->next         = newblock;
666     newblock->previous = next;
667   }
668   mb->numBlocks++;
669   PetscFunctionReturn(0);
670 }
671 EXTERN_C_END
672 
673 EXTERN_C_BEGIN
674 #undef __FUNCT__
675 #define __FUNCT__ "SNESMultiblockSetIS_Default"
676 PetscErrorCode SNESMultiblockSetIS_Default(SNES snes, const char name[], IS is)
677 {
678   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
679   BlockDesc        newblock, next = mb->blocks;
680   char             prefix[128];
681   PetscErrorCode   ierr;
682 
683   PetscFunctionBegin;
684   if (mb->defined) {
685     ierr = PetscInfo1(snes, "Ignoring new block \"%s\" because the blocks have already been defined\n", name);CHKERRQ(ierr);
686     PetscFunctionReturn(0);
687   }
688   ierr = PetscNew(struct _BlockDesc, &newblock);CHKERRQ(ierr);
689   if (name) {
690     ierr = PetscStrallocpy(name, &newblock->name);CHKERRQ(ierr);
691   } else {
692     PetscInt len = floor(log10(mb->numBlocks))+1;
693 
694     ierr = PetscMalloc((len+1)*sizeof(char), &newblock->name);CHKERRQ(ierr);
695     ierr = PetscSNPrintf(newblock->name, len, "%s", mb->numBlocks);CHKERRQ(ierr);
696   }
697   newblock->is   = is;
698   ierr = PetscObjectReference((PetscObject) is);CHKERRQ(ierr);
699   newblock->next = PETSC_NULL;
700   ierr = SNESCreate(((PetscObject) snes)->comm, &newblock->snes);CHKERRQ(ierr);
701   ierr = PetscObjectIncrementTabLevel((PetscObject) newblock->snes, (PetscObject) snes, 1);CHKERRQ(ierr);
702   ierr = SNESSetType(newblock->snes, SNESPICARD);CHKERRQ(ierr);
703   ierr = PetscLogObjectParent((PetscObject) snes, (PetscObject) newblock->snes);CHKERRQ(ierr);
704   ierr = PetscSNPrintf(prefix, sizeof prefix, "%smultiblock_%s_", ((PetscObject) snes)->prefix ? ((PetscObject) snes)->prefix : "", newblock->name);CHKERRQ(ierr);
705   ierr = SNESSetOptionsPrefix(newblock->snes, prefix);CHKERRQ(ierr);
706 
707   if (!next) {
708     mb->blocks         = newblock;
709     newblock->previous = PETSC_NULL;
710   } else {
711     while (next->next) {
712       next = next->next;
713     }
714     next->next         = newblock;
715     newblock->previous = next;
716   }
717   mb->numBlocks++;
718   PetscFunctionReturn(0);
719 }
720 EXTERN_C_END
721 
722 EXTERN_C_BEGIN
723 #undef __FUNCT__
724 #define __FUNCT__ "SNESMultiblockSetType_Default"
725 PetscErrorCode  SNESMultiblockSetType_Default(SNES snes, PCCompositeType type)
726 {
727   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
728   PetscErrorCode   ierr;
729 
730   PetscFunctionBegin;
731   mb->type = type;
732   if (type == PC_COMPOSITE_SCHUR) {
733 #if 1
734     SETERRQ(((PetscObject) snes)->comm, PETSC_ERR_SUP, "The Schur composite type is not yet supported");
735 #else
736     snes->ops->solve = SNESApply_Multiblock_Schur;
737     snes->ops->view  = SNESView_Multiblock_Schur;
738     ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockGetSubSNES_C", "SNESMultiblockGetSubSNES_Schur", SNESMultiblockGetSubSNES_Schur);CHKERRQ(ierr);
739     ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSchurPrecondition_C", "SNESMultiblockSchurPrecondition_Default", SNESMultiblockSchurPrecondition_Default);CHKERRQ(ierr);
740 #endif
741   } else {
742     snes->ops->solve = SNESApply_Multiblock;
743     snes->ops->view  = SNESView_Multiblock;
744     ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockGetSubSNES_C", "SNESMultiblockGetSubSNES_Default", SNESMultiblockGetSubSNES_Default);CHKERRQ(ierr);
745     ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSchurPrecondition_C", "", 0);CHKERRQ(ierr);
746   }
747   PetscFunctionReturn(0);
748 }
749 EXTERN_C_END
750 
751 EXTERN_C_BEGIN
752 #undef __FUNCT__
753 #define __FUNCT__ "SNESMultiblockSetBlockSize_Default"
754 PetscErrorCode  SNESMultiblockSetBlockSize_Default(SNES snes, PetscInt bs)
755 {
756   SNES_Multiblock *mb = (SNES_Multiblock *) snes->data;
757 
758   PetscFunctionBegin;
759   if (bs < 1) {SETERRQ1(((PetscObject) snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %D", bs);}
760   if (mb->bs > 0 && mb->bs != bs) {SETERRQ2(((PetscObject) snes)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot change blocksize from %D to %D after it has been set", mb->bs, bs);}
761   mb->bs = bs;
762   PetscFunctionReturn(0);
763 }
764 EXTERN_C_END
765 
766 EXTERN_C_BEGIN
767 #undef __FUNCT__
768 #define __FUNCT__ "SNESMultiblockGetSubSNES_Default"
769 PetscErrorCode SNESMultiblockGetSubSNES_Default(SNES snes, PetscInt *n, SNES **subsnes)
770 {
771   SNES_Multiblock *mb     = (SNES_Multiblock *) snes->data;
772   BlockDesc        blocks = mb->blocks;
773   PetscInt         cnt    = 0;
774   PetscErrorCode   ierr;
775 
776   PetscFunctionBegin;
777   ierr = PetscMalloc(mb->numBlocks * sizeof(SNES), subsnes);CHKERRQ(ierr);
778   while (blocks) {
779     (*subsnes)[cnt++] = blocks->snes;
780     blocks = blocks->next;
781   }
782   if (cnt != mb->numBlocks) {
783     SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Corrupt SNESMULTIBLOCK object: number of blocks in linked list %D does not match number in object %D", cnt, mb->numBlocks);
784   }
785   if (n) {*n = mb->numBlocks;}
786   PetscFunctionReturn(0);
787 }
788 EXTERN_C_END
789 
790 #undef __FUNCT__
791 #define __FUNCT__ "SNESMultiblockSetFields"
792 /*@
793   SNESMultiblockSetFields - Sets the fields for one particular block in the solver
794 
795   Logically Collective on SNES
796 
797   Input Parameters:
798 + snes   - the solver
799 . name   - name of this block, if PETSC_NULL the number of the block is used
800 . n      - the number of fields in this block
801 - fields - the fields in this block
802 
803   Level: intermediate
804 
805   Notes: Use SNESMultiblockSetIS() to set a completely general set of row indices as a block.
806 
807   The SNESMultiblockSetFields() is for defining blocks as a group of strided indices, or fields.
808   For example, if the vector block size is three then one can define a block as field 0, or
809   1 or 2, or field 0,1 or 0,2 or 1,2 which means
810     0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
811   where the numbered entries indicate what is in the block.
812 
813   This function is called once per block (it creates a new block each time). Solve options
814   for this block will be available under the prefix -multiblock_BLOCKNAME_.
815 
816 .seealso: SNESMultiblockGetSubKSP(), SNESMULTIBLOCK, SNESMultiblockSetBlockSize(), SNESMultiblockSetIS()
817 @*/
818 PetscErrorCode SNESMultiblockSetFields(SNES snes, const char name[], PetscInt n, const PetscInt *fields)
819 {
820   PetscErrorCode ierr;
821 
822   PetscFunctionBegin;
823   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
824   PetscValidCharPointer(name, 2);
825   if (n < 1) SETERRQ2(((PetscObject) snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %D in split \"%s\" not positive", n, name);
826   PetscValidIntPointer(fields, 3);
827   ierr = PetscTryMethod(snes, "SNESMultiblockSetFields_C", (SNES, const char[], PetscInt, const PetscInt *), (snes, name, n, fields));CHKERRQ(ierr);
828   PetscFunctionReturn(0);
829 }
830 
831 #undef __FUNCT__
832 #define __FUNCT__ "SNESMultiblockSetIS"
833 /*@
834   SNESMultiblockSetIS - Sets the global row indices for the block
835 
836   Logically Collective on SNES
837 
838   Input Parameters:
839 + snes - the solver context
840 . name - name of this block, if PETSC_NULL the number of the block is used
841 - is   - the index set that defines the global row indices in this block
842 
843   Notes:
844   Use SNESMultiblockSetFields(), for blocks defined by strides.
845 
846   This function is called once per block (it creates a new block each time). Solve options
847   for this block will be available under the prefix -multiblock_BLOCKNAME_.
848 
849   Level: intermediate
850 
851 .seealso: SNESMultiblockGetSubKSP(), SNESMULTIBLOCK, SNESMultiblockSetBlockSize()
852 @*/
853 PetscErrorCode SNESMultiblockSetIS(SNES snes, const char name[], IS is)
854 {
855   PetscErrorCode ierr;
856 
857   PetscFunctionBegin;
858   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
859   PetscValidCharPointer(name, 2);
860   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
861   ierr = PetscTryMethod(snes, "SNESMultiblockSetIS_C", (SNES, const char[], IS), (snes, name, is));CHKERRQ(ierr);
862   PetscFunctionReturn(0);
863 }
864 
865 #undef __FUNCT__
866 #define __FUNCT__ "SNESMultiblockSetType"
867 /*@
868   SNESMultiblockSetType - Sets the type of block combination.
869 
870   Collective on SNES
871 
872   Input Parameters:
873 + snes - the solver context
874 - type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE
875 
876   Options Database Key:
877 . -snes_multiblock_type <type: one of multiplicative, additive, symmetric_multiplicative> - Sets block combination type
878 
879   Level: Developer
880 
881 .keywords: SNES, set, type, composite preconditioner, additive, multiplicative
882 .seealso: PCCompositeSetType()
883 @*/
884 PetscErrorCode SNESMultiblockSetType(SNES snes, PCCompositeType type)
885 {
886   PetscErrorCode ierr;
887 
888   PetscFunctionBegin;
889   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
890   ierr = PetscTryMethod(snes, "SNESMultiblockSetType_C", (SNES, PCCompositeType), (snes, type));CHKERRQ(ierr);
891   PetscFunctionReturn(0);
892 }
893 
894 #undef __FUNCT__
895 #define __FUNCT__ "SNESMultiblockSetBlockSize"
896 /*@
897   SNESMultiblockSetBlockSize - Sets the block size for structured mesh block division. If not set the matrix block size is used.
898 
899   Logically Collective on SNES
900 
901   Input Parameters:
902 + snes - the solver context
903 - bs   - the block size
904 
905   Level: intermediate
906 
907 .seealso: SNESMultiblockGetSubKSP(), SNESMULTIBLOCK, SNESMultiblockSetFields()
908 @*/
909 PetscErrorCode  SNESMultiblockSetBlockSize(SNES snes, PetscInt bs)
910 {
911   PetscErrorCode ierr;
912 
913   PetscFunctionBegin;
914   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
915   PetscValidLogicalCollectiveInt(snes, bs, 2);
916   ierr = PetscTryMethod(snes, "SNESMultiblockSetBlockSize_C", (SNES, PetscInt), (snes,bs));CHKERRQ(ierr);
917   PetscFunctionReturn(0);
918 }
919 
920 #undef __FUNCT__
921 #define __FUNCT__ "SNESMultiblockGetSubSNES"
922 /*@C
923   SNESMultiblockGetSubKSP - Gets the SNES contexts for all blocks
924 
925   Collective on SNES
926 
927   Input Parameter:
928 . snes - the solver context
929 
930   Output Parameters:
931 + n       - the number of blocks
932 - subsnes - the array of SNES contexts
933 
934   Note:
935   After SNESMultiblockGetSubSNES() the array of SNESs MUST be freed by the user
936   (not each SNES, just the array that contains them).
937 
938   You must call SNESSetUp() before calling SNESMultiblockGetSubSNES().
939 
940   Level: advanced
941 
942 .seealso: SNESMULTIBLOCK
943 @*/
944 PetscErrorCode SNESMultiblockGetSubSNES(SNES snes, PetscInt *n, SNES *subsnes[])
945 {
946   PetscErrorCode ierr;
947 
948   PetscFunctionBegin;
949   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
950   if (n) PetscValidIntPointer(n, 2);
951   ierr = PetscUseMethod(snes, "SNESMultiblockGetSubKSP_C", (SNES, PetscInt*, KSP **), (snes, n, subsnes));CHKERRQ(ierr);
952   PetscFunctionReturn(0);
953 }
954 
955 /*MC
956   SNESMULTIBLOCK - Multiblock nonlinear solver that can use overlapping or nonoverlapping blocks, organized
957   additively (Jacobi) or multiplicatively (Gauss-Seidel).
958 
959   Level: beginner
960 
961 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESLS, SNESTR, SNESPICARD
962 M*/
963 EXTERN_C_BEGIN
964 #undef __FUNCT__
965 #define __FUNCT__ "SNESCreate_Multiblock"
966 PetscErrorCode  SNESCreate_Multiblock(SNES snes)
967 {
968   SNES_Multiblock *mb;
969   PetscErrorCode   ierr;
970 
971   PetscFunctionBegin;
972   snes->ops->destroy	    = SNESDestroy_Multiblock;
973   snes->ops->setup	    = SNESSetUp_Multiblock;
974   snes->ops->setfromoptions = SNESSetFromOptions_Multiblock;
975   snes->ops->view           = SNESView_Multiblock;
976   snes->ops->solve	    = SNESSolve_Multiblock;
977   snes->ops->reset          = SNESReset_Multiblock;
978 
979   ierr = PetscNewLog(snes, SNES_Multiblock, &mb);CHKERRQ(ierr);
980   snes->data = (void*) mb;
981   mb->defined   = PETSC_FALSE;
982   mb->numBlocks = 0;
983   mb->bs        = -1;
984   mb->type      = PC_COMPOSITE_MULTIPLICATIVE;
985 
986   /* We attach functions so that they can be called on another PC without crashing the program */
987   ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSetFields_C",    "SNESMultiblockSetFields_Default",    SNESMultiblockSetFields_Default);CHKERRQ(ierr);
988   ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSetIS_C",        "SNESMultiblockSetIS_Default",        SNESMultiblockSetIS_Default);CHKERRQ(ierr);
989   ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSetType_C",      "SNESMultiblockSetType_Default",      SNESMultiblockSetType_Default);CHKERRQ(ierr);
990   ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSetBlockSize_C", "SNESMultiblockSetBlockSize_Default", SNESMultiblockSetBlockSize_Default);CHKERRQ(ierr);
991   ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockGetSubSNES_C",   "SNESMultiblockGetSubSNES_Default",   SNESMultiblockGetSubSNES_Default);CHKERRQ(ierr);
992   PetscFunctionReturn(0);
993 }
994 EXTERN_C_END
995