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