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