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