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