xref: /petsc/src/snes/impls/multiblock/multiblock.c (revision bd89dbf26d8a5efecb980364933175da61864cd7)
1af0996ceSBarry Smith #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/
2b665c654SMatthew G Knepley #include <petscdmcomposite.h>
3c7543cceSMatthew G Knepley 
4c7543cceSMatthew G Knepley typedef struct _BlockDesc *BlockDesc;
5c7543cceSMatthew G Knepley struct _BlockDesc {
6c7543cceSMatthew G Knepley   char      *name;    /* Block name */
7c7543cceSMatthew G Knepley   PetscInt   nfields; /* If block is defined on a DA, the number of DA fields */
8c7543cceSMatthew G Knepley   PetscInt  *fields;  /* If block is defined on a DA, the list of DA fields */
9c7543cceSMatthew G Knepley   IS         is;      /* Index sets defining the block */
10c7543cceSMatthew G Knepley   VecScatter sctx;    /* Scatter mapping global Vec to blockVec */
11c7543cceSMatthew G Knepley   SNES       snes;    /* Solver for this block */
12c7543cceSMatthew G Knepley   Vec        x;
13c7543cceSMatthew G Knepley   BlockDesc  next, previous;
14c7543cceSMatthew G Knepley };
15c7543cceSMatthew G Knepley 
16c7543cceSMatthew G Knepley typedef struct {
17c7543cceSMatthew G Knepley   PetscBool       issetup;       /* Flag is true after the all ISs and operators have been defined */
18c7543cceSMatthew G Knepley   PetscBool       defined;       /* Flag is true after the blocks have been defined, to prevent more blocks from being added */
19c7543cceSMatthew G Knepley   PetscBool       defaultblocks; /* Flag is true for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
20c7543cceSMatthew G Knepley   PetscInt        numBlocks;     /* Number of blocks (can be fields, domains, etc.) */
21c7543cceSMatthew G Knepley   PetscInt        bs;            /* Block size for IS, Vec and Mat structures */
22c7543cceSMatthew G Knepley   PCCompositeType type;          /* Solver combination method (additive, multiplicative, etc.) */
23c7543cceSMatthew G Knepley   BlockDesc       blocks;        /* Linked list of block descriptors */
24c7543cceSMatthew G Knepley } SNES_Multiblock;
25c7543cceSMatthew G Knepley 
SNESReset_Multiblock(SNES snes)2666976f2fSJacob Faibussowitsch static PetscErrorCode SNESReset_Multiblock(SNES snes)
27d71ae5a4SJacob Faibussowitsch {
28c7543cceSMatthew G Knepley   SNES_Multiblock *mb     = (SNES_Multiblock *)snes->data;
29c7543cceSMatthew G Knepley   BlockDesc        blocks = mb->blocks, next;
30c7543cceSMatthew G Knepley 
31c7543cceSMatthew G Knepley   PetscFunctionBegin;
32c7543cceSMatthew G Knepley   while (blocks) {
339566063dSJacob Faibussowitsch     PetscCall(SNESReset(blocks->snes));
340c74a584SJed Brown #if 0
359566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&blocks->x));
360c74a584SJed Brown #endif
379566063dSJacob Faibussowitsch     PetscCall(VecScatterDestroy(&blocks->sctx));
389566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&blocks->is));
39c7543cceSMatthew G Knepley     next   = blocks->next;
40c7543cceSMatthew G Knepley     blocks = next;
41c7543cceSMatthew G Knepley   }
423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43c7543cceSMatthew G Knepley }
44c7543cceSMatthew G Knepley 
45c7543cceSMatthew G Knepley /*
46c7543cceSMatthew G Knepley   SNESDestroy_Multiblock - Destroys the private SNES_Multiblock context that was created with SNESCreate_Multiblock().
47c7543cceSMatthew G Knepley 
48c7543cceSMatthew G Knepley   Input Parameter:
49c7543cceSMatthew G Knepley . snes - the SNES context
50c7543cceSMatthew G Knepley 
51c7543cceSMatthew G Knepley   Application Interface Routine: SNESDestroy()
52c7543cceSMatthew G Knepley */
SNESDestroy_Multiblock(SNES snes)5366976f2fSJacob Faibussowitsch static PetscErrorCode SNESDestroy_Multiblock(SNES snes)
54d71ae5a4SJacob Faibussowitsch {
55c7543cceSMatthew G Knepley   SNES_Multiblock *mb     = (SNES_Multiblock *)snes->data;
56c7543cceSMatthew G Knepley   BlockDesc        blocks = mb->blocks, next;
57c7543cceSMatthew G Knepley 
58c7543cceSMatthew G Knepley   PetscFunctionBegin;
599566063dSJacob Faibussowitsch   PetscCall(SNESReset_Multiblock(snes));
60c7543cceSMatthew G Knepley   while (blocks) {
61c7543cceSMatthew G Knepley     next = blocks->next;
629566063dSJacob Faibussowitsch     PetscCall(SNESDestroy(&blocks->snes));
639566063dSJacob Faibussowitsch     PetscCall(PetscFree(blocks->name));
649566063dSJacob Faibussowitsch     PetscCall(PetscFree(blocks->fields));
659566063dSJacob Faibussowitsch     PetscCall(PetscFree(blocks));
66c7543cceSMatthew G Knepley     blocks = next;
67c7543cceSMatthew G Knepley   }
689566063dSJacob Faibussowitsch   PetscCall(PetscFree(snes->data));
693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
70c7543cceSMatthew G Knepley }
71c7543cceSMatthew G Knepley 
72c7543cceSMatthew G Knepley /* Precondition: blocksize is set to a meaningful value */
SNESMultiblockSetFieldsRuntime_Private(SNES snes)73d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESMultiblockSetFieldsRuntime_Private(SNES snes)
74d71ae5a4SJacob Faibussowitsch {
75c7543cceSMatthew G Knepley   SNES_Multiblock *mb = (SNES_Multiblock *)snes->data;
76c7543cceSMatthew G Knepley   PetscInt        *ifields;
77c7543cceSMatthew G Knepley   PetscInt         i, nfields;
78c7543cceSMatthew G Knepley   PetscBool        flg = PETSC_TRUE;
79c7543cceSMatthew G Knepley   char             optionname[128], name[8];
80c7543cceSMatthew G Knepley 
81c7543cceSMatthew G Knepley   PetscFunctionBegin;
829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mb->bs, &ifields));
83c7543cceSMatthew G Knepley   for (i = 0;; ++i) {
8463a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(name, sizeof(name), "%" PetscInt_FMT, i));
8563a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(optionname, sizeof(optionname), "-snes_multiblock_%" PetscInt_FMT "_fields", i));
86c7543cceSMatthew G Knepley     nfields = mb->bs;
879566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetIntArray(NULL, ((PetscObject)snes)->prefix, optionname, ifields, &nfields, &flg));
88c7543cceSMatthew G Knepley     if (!flg) break;
8928b400f6SJacob Faibussowitsch     PetscCheck(nfields, PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields");
909566063dSJacob Faibussowitsch     PetscCall(SNESMultiblockSetFields(snes, name, nfields, ifields));
91c7543cceSMatthew G Knepley   }
92c7543cceSMatthew G Knepley   if (i > 0) {
93c7543cceSMatthew G Knepley     /* Makes command-line setting of blocks take precedence over setting them in code.
94c7543cceSMatthew G Knepley        Otherwise subsequent calls to SNESMultiblockSetIS() or SNESMultiblockSetFields() would
95c7543cceSMatthew G Knepley        create new blocks, which would probably not be what the user wanted. */
96c7543cceSMatthew G Knepley     mb->defined = PETSC_TRUE;
97c7543cceSMatthew G Knepley   }
989566063dSJacob Faibussowitsch   PetscCall(PetscFree(ifields));
993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
100c7543cceSMatthew G Knepley }
101c7543cceSMatthew G Knepley 
SNESMultiblockSetDefaults(SNES snes)102d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESMultiblockSetDefaults(SNES snes)
103d71ae5a4SJacob Faibussowitsch {
104c7543cceSMatthew G Knepley   SNES_Multiblock *mb     = (SNES_Multiblock *)snes->data;
105c7543cceSMatthew G Knepley   BlockDesc        blocks = mb->blocks;
106c7543cceSMatthew G Knepley   PetscInt         i;
107c7543cceSMatthew G Knepley 
108c7543cceSMatthew G Knepley   PetscFunctionBegin;
109c7543cceSMatthew G Knepley   if (!blocks) {
110c7543cceSMatthew G Knepley     if (snes->dm) {
111c7543cceSMatthew G Knepley       PetscBool dmcomposite;
112c7543cceSMatthew G Knepley 
1139566063dSJacob Faibussowitsch       PetscCall(PetscObjectTypeCompare((PetscObject)snes->dm, DMCOMPOSITE, &dmcomposite));
114c7543cceSMatthew G Knepley       if (dmcomposite) {
115c7543cceSMatthew G Knepley         PetscInt nDM;
116c7543cceSMatthew G Knepley         IS      *fields;
117c7543cceSMatthew G Knepley 
1189566063dSJacob Faibussowitsch         PetscCall(PetscInfo(snes, "Setting up physics based multiblock solver using the embedded DM\n"));
1199566063dSJacob Faibussowitsch         PetscCall(DMCompositeGetNumberDM(snes->dm, &nDM));
1209566063dSJacob Faibussowitsch         PetscCall(DMCompositeGetGlobalISs(snes->dm, &fields));
121c7543cceSMatthew G Knepley         for (i = 0; i < nDM; ++i) {
122c7543cceSMatthew G Knepley           char name[8];
123c7543cceSMatthew G Knepley 
12463a3b9bcSJacob Faibussowitsch           PetscCall(PetscSNPrintf(name, sizeof(name), "%" PetscInt_FMT, i));
1259566063dSJacob Faibussowitsch           PetscCall(SNESMultiblockSetIS(snes, name, fields[i]));
1269566063dSJacob Faibussowitsch           PetscCall(ISDestroy(&fields[i]));
127c7543cceSMatthew G Knepley         }
1289566063dSJacob Faibussowitsch         PetscCall(PetscFree(fields));
129c7543cceSMatthew G Knepley       }
130c7543cceSMatthew G Knepley     } else {
131c7543cceSMatthew G Knepley       PetscBool flg    = PETSC_FALSE;
132c7543cceSMatthew G Knepley       PetscBool stokes = PETSC_FALSE;
133c7543cceSMatthew G Knepley 
134c7543cceSMatthew G Knepley       if (mb->bs <= 0) {
135ac530a7eSPierre Jolivet         if (snes->jacobian_pre) PetscCall(MatGetBlockSize(snes->jacobian_pre, &mb->bs));
136ac530a7eSPierre Jolivet         else mb->bs = 1;
137c7543cceSMatthew G Knepley       }
138c7543cceSMatthew G Knepley 
1399566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)snes)->prefix, "-snes_multiblock_default", &flg, NULL));
1409566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(NULL, ((PetscObject)snes)->prefix, "-snes_multiblock_detect_saddle_point", &stokes, NULL));
141c7543cceSMatthew G Knepley       if (stokes) {
142c7543cceSMatthew G Knepley         IS       zerodiags, rest;
143c7543cceSMatthew G Knepley         PetscInt nmin, nmax;
144c7543cceSMatthew G Knepley 
1459566063dSJacob Faibussowitsch         PetscCall(MatGetOwnershipRange(snes->jacobian_pre, &nmin, &nmax));
1469566063dSJacob Faibussowitsch         PetscCall(MatFindZeroDiagonals(snes->jacobian_pre, &zerodiags));
1479566063dSJacob Faibussowitsch         PetscCall(ISComplement(zerodiags, nmin, nmax, &rest));
1489566063dSJacob Faibussowitsch         PetscCall(SNESMultiblockSetIS(snes, "0", rest));
1499566063dSJacob Faibussowitsch         PetscCall(SNESMultiblockSetIS(snes, "1", zerodiags));
1509566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&zerodiags));
1519566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&rest));
152c7543cceSMatthew G Knepley       } else {
153c7543cceSMatthew G Knepley         if (!flg) {
154c7543cceSMatthew G Knepley           /* Allow user to set fields from command line, if bs was known at the time of SNESSetFromOptions_Multiblock()
155c7543cceSMatthew G Knepley            then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
1569566063dSJacob Faibussowitsch           PetscCall(SNESMultiblockSetFieldsRuntime_Private(snes));
1579566063dSJacob Faibussowitsch           if (mb->defined) PetscCall(PetscInfo(snes, "Blocks defined using the options database\n"));
158c7543cceSMatthew G Knepley         }
159c7543cceSMatthew G Knepley         if (flg || !mb->defined) {
1609566063dSJacob Faibussowitsch           PetscCall(PetscInfo(snes, "Using default splitting of fields\n"));
161c7543cceSMatthew G Knepley           for (i = 0; i < mb->bs; ++i) {
162c7543cceSMatthew G Knepley             char name[8];
163c7543cceSMatthew G Knepley 
16463a3b9bcSJacob Faibussowitsch             PetscCall(PetscSNPrintf(name, sizeof(name), "%" PetscInt_FMT, i));
1659566063dSJacob Faibussowitsch             PetscCall(SNESMultiblockSetFields(snes, name, 1, &i));
166c7543cceSMatthew G Knepley           }
167c7543cceSMatthew G Knepley           mb->defaultblocks = PETSC_TRUE;
168c7543cceSMatthew G Knepley         }
169c7543cceSMatthew G Knepley       }
170c7543cceSMatthew G Knepley     }
171c7543cceSMatthew G Knepley   } else if (mb->numBlocks == 1) {
172c7543cceSMatthew G Knepley     IS       is2;
173c7543cceSMatthew G Knepley     PetscInt nmin, nmax;
174c7543cceSMatthew G Knepley 
175966bd95aSPierre Jolivet     PetscCheck(blocks->is, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least two sets of fields to SNES multiblock");
1769566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(snes->jacobian_pre, &nmin, &nmax));
1779566063dSJacob Faibussowitsch     PetscCall(ISComplement(blocks->is, nmin, nmax, &is2));
1789566063dSJacob Faibussowitsch     PetscCall(SNESMultiblockSetIS(snes, "1", is2));
1799566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&is2));
180c7543cceSMatthew G Knepley   }
18108401ef6SPierre Jolivet   PetscCheck(mb->numBlocks >= 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unhandled case, must have at least two blocks");
1823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
183c7543cceSMatthew G Knepley }
184c7543cceSMatthew G Knepley 
SNESSetUp_Multiblock(SNES snes)18566976f2fSJacob Faibussowitsch static PetscErrorCode SNESSetUp_Multiblock(SNES snes)
186d71ae5a4SJacob Faibussowitsch {
187c7543cceSMatthew G Knepley   SNES_Multiblock *mb = (SNES_Multiblock *)snes->data;
188c7543cceSMatthew G Knepley   BlockDesc        blocks;
189c7543cceSMatthew G Knepley   PetscInt         i, numBlocks;
190c7543cceSMatthew G Knepley 
191c7543cceSMatthew G Knepley   PetscFunctionBegin;
1929566063dSJacob Faibussowitsch   PetscCall(SNESMultiblockSetDefaults(snes));
193c7543cceSMatthew G Knepley   numBlocks = mb->numBlocks;
194b665c654SMatthew G Knepley   blocks    = mb->blocks;
195c7543cceSMatthew G Knepley 
196c7543cceSMatthew G Knepley   /* Create ISs */
197c7543cceSMatthew G Knepley   if (!mb->issetup) {
198c7543cceSMatthew G Knepley     PetscInt  ccsize, rstart, rend, nslots, bs;
199c7543cceSMatthew G Knepley     PetscBool sorted;
200c7543cceSMatthew G Knepley 
201c7543cceSMatthew G Knepley     mb->issetup = PETSC_TRUE;
202c7543cceSMatthew G Knepley     bs          = mb->bs;
2039566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRange(snes->jacobian_pre, &rstart, &rend));
2049566063dSJacob Faibussowitsch     PetscCall(MatGetLocalSize(snes->jacobian_pre, NULL, &ccsize));
205c7543cceSMatthew G Knepley     nslots = (rend - rstart) / bs;
206c7543cceSMatthew G Knepley     for (i = 0; i < numBlocks; ++i) {
207b665c654SMatthew G Knepley       if (mb->defaultblocks) {
2089566063dSJacob Faibussowitsch         PetscCall(ISCreateStride(PetscObjectComm((PetscObject)snes), nslots, rstart + i, numBlocks, &blocks->is));
209c7543cceSMatthew G Knepley       } else if (!blocks->is) {
210c7543cceSMatthew G Knepley         if (blocks->nfields > 1) {
211c7543cceSMatthew G Knepley           PetscInt *ii, j, k, nfields = blocks->nfields, *fields = blocks->fields;
212c7543cceSMatthew G Knepley 
2139566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nfields * nslots, &ii));
214c7543cceSMatthew G Knepley           for (j = 0; j < nslots; ++j) {
215ad540459SPierre Jolivet             for (k = 0; k < nfields; ++k) ii[nfields * j + k] = rstart + bs * j + fields[k];
216c7543cceSMatthew G Knepley           }
2179566063dSJacob Faibussowitsch           PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)snes), nslots * nfields, ii, PETSC_OWN_POINTER, &blocks->is));
218c7543cceSMatthew G Knepley         } else {
2199566063dSJacob Faibussowitsch           PetscCall(ISCreateStride(PetscObjectComm((PetscObject)snes), nslots, rstart + blocks->fields[0], bs, &blocks->is));
220c7543cceSMatthew G Knepley         }
221c7543cceSMatthew G Knepley       }
2229566063dSJacob Faibussowitsch       PetscCall(ISSorted(blocks->is, &sorted));
22328b400f6SJacob Faibussowitsch       PetscCheck(sorted, PETSC_COMM_SELF, PETSC_ERR_USER, "Fields must be sorted when creating split");
224c7543cceSMatthew G Knepley       blocks = blocks->next;
225c7543cceSMatthew G Knepley     }
226c7543cceSMatthew G Knepley   }
227c7543cceSMatthew G Knepley 
228c7543cceSMatthew G Knepley #if 0
229c7543cceSMatthew G Knepley   /* Create matrices */
230c7543cceSMatthew G Knepley   ilink = jac->head;
231c7543cceSMatthew G Knepley   if (!jac->pmat) {
2329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nsplit,&jac->pmat));
233c7543cceSMatthew G Knepley     for (i=0; i<nsplit; i++) {
2349566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]));
235c7543cceSMatthew G Knepley       ilink = ilink->next;
236c7543cceSMatthew G Knepley     }
237c7543cceSMatthew G Knepley   } else {
238c7543cceSMatthew G Knepley     for (i=0; i<nsplit; i++) {
2399566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]));
240c7543cceSMatthew G Knepley       ilink = ilink->next;
241c7543cceSMatthew G Knepley     }
242c7543cceSMatthew G Knepley   }
243c7543cceSMatthew G Knepley   if (jac->realdiagonal) {
244c7543cceSMatthew G Knepley     ilink = jac->head;
245c7543cceSMatthew G Knepley     if (!jac->mat) {
2469566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nsplit,&jac->mat));
247c7543cceSMatthew G Knepley       for (i=0; i<nsplit; i++) {
2489566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]));
249c7543cceSMatthew G Knepley         ilink = ilink->next;
250c7543cceSMatthew G Knepley       }
251c7543cceSMatthew G Knepley     } else {
252c7543cceSMatthew G Knepley       for (i=0; i<nsplit; i++) {
2539566063dSJacob Faibussowitsch         if (jac->mat[i]) PetscCall(MatCreateSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]));
254c7543cceSMatthew G Knepley         ilink = ilink->next;
255c7543cceSMatthew G Knepley       }
256c7543cceSMatthew G Knepley     }
2571aa26658SKarl Rupp   } else jac->mat = jac->pmat;
258c7543cceSMatthew G Knepley #endif
259c7543cceSMatthew G Knepley 
260c7543cceSMatthew G Knepley #if 0
261c7543cceSMatthew G Knepley   if (jac->type != PC_COMPOSITE_ADDITIVE  && jac->type != PC_COMPOSITE_SCHUR) {
262c7543cceSMatthew G Knepley     /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
263c7543cceSMatthew G Knepley     ilink = jac->head;
264c7543cceSMatthew G Knepley     if (!jac->Afield) {
2659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nsplit,&jac->Afield));
266c7543cceSMatthew G Knepley       for (i=0; i<nsplit; i++) {
2679566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(pc->mat,ilink->is,NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]));
268c7543cceSMatthew G Knepley         ilink = ilink->next;
269c7543cceSMatthew G Knepley       }
270c7543cceSMatthew G Knepley     } else {
271c7543cceSMatthew G Knepley       for (i=0; i<nsplit; i++) {
2729566063dSJacob Faibussowitsch         PetscCall(MatCreateSubMatrix(pc->mat,ilink->is,NULL,MAT_REUSE_MATRIX,&jac->Afield[i]));
273c7543cceSMatthew G Knepley         ilink = ilink->next;
274c7543cceSMatthew G Knepley       }
275c7543cceSMatthew G Knepley     }
276c7543cceSMatthew G Knepley   }
277c7543cceSMatthew G Knepley #endif
278c7543cceSMatthew G Knepley 
279b665c654SMatthew G Knepley   if (mb->type == PC_COMPOSITE_SCHUR) {
280c7543cceSMatthew G Knepley #if 0
281c7543cceSMatthew G Knepley     IS       ccis;
282c7543cceSMatthew G Knepley     PetscInt rstart,rend;
28308401ef6SPierre Jolivet     PetscCheck(nsplit == 2,PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
284c7543cceSMatthew G Knepley 
285c7543cceSMatthew G Knepley     /* When extracting off-diagonal submatrices, we take complements from this range */
2869566063dSJacob Faibussowitsch     PetscCall(MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend));
287c7543cceSMatthew G Knepley 
288c7543cceSMatthew G Knepley     /* need to handle case when one is resetting up the preconditioner */
289c7543cceSMatthew G Knepley     if (jac->schur) {
290c7543cceSMatthew G Knepley       ilink = jac->head;
2919566063dSJacob Faibussowitsch       PetscCall(ISComplement(ilink->is,rstart,rend,&ccis));
2929566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B));
2939566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&ccis));
294c7543cceSMatthew G Knepley       ilink = ilink->next;
2959566063dSJacob Faibussowitsch       PetscCall(ISComplement(ilink->is,rstart,rend,&ccis));
2969566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C));
2979566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&ccis));
2989566063dSJacob Faibussowitsch       PetscCall(MatSchurComplementUpdateSubMatrices(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1]));
2999566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag));
300c7543cceSMatthew G Knepley 
301c7543cceSMatthew G Knepley     } else {
302c7543cceSMatthew G Knepley       KSP  ksp;
303c7543cceSMatthew G Knepley       char schurprefix[256];
304c7543cceSMatthew G Knepley 
305c7543cceSMatthew G Knepley       /* extract the A01 and A10 matrices */
306c7543cceSMatthew G Knepley       ilink = jac->head;
3079566063dSJacob Faibussowitsch       PetscCall(ISComplement(ilink->is,rstart,rend,&ccis));
3089566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B));
3099566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&ccis));
310c7543cceSMatthew G Knepley       ilink = ilink->next;
3119566063dSJacob Faibussowitsch       PetscCall(ISComplement(ilink->is,rstart,rend,&ccis));
3129566063dSJacob Faibussowitsch       PetscCall(MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C));
3139566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&ccis));
314c7543cceSMatthew G Knepley       /* Use mat[0] (diagonal block of the real matrix) preconditioned by pmat[0] */
3159566063dSJacob Faibussowitsch       PetscCall(MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur));
316c7543cceSMatthew G Knepley       /* set tabbing and options prefix of KSP inside the MatSchur */
3179566063dSJacob Faibussowitsch       PetscCall(MatSchurComplementGetKSP(jac->schur,&ksp));
3189566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2));
3199566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(schurprefix,sizeof(schurprefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",jac->head->splitname));
3209566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(ksp,schurprefix));
3219566063dSJacob Faibussowitsch       PetscCall(MatSetFromOptions(jac->schur));
322c7543cceSMatthew G Knepley 
3239566063dSJacob Faibussowitsch       PetscCall(KSPCreate(PetscObjectComm((PetscObject)pc),&jac->kspschur));
3249566063dSJacob Faibussowitsch       PetscCall(PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1));
3259566063dSJacob Faibussowitsch       PetscCall(KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac)));
326c7543cceSMatthew G Knepley       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
327c7543cceSMatthew G Knepley         PC pc;
3289566063dSJacob Faibussowitsch         PetscCall(KSPGetPC(jac->kspschur,&pc));
3299566063dSJacob Faibussowitsch         PetscCall(PCSetType(pc,PCNONE));
330c7543cceSMatthew G Knepley         /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
331c7543cceSMatthew G Knepley       }
3329566063dSJacob Faibussowitsch       PetscCall(PetscSNPrintf(schurprefix,sizeof(schurprefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname));
3339566063dSJacob Faibussowitsch       PetscCall(KSPSetOptionsPrefix(jac->kspschur,schurprefix));
334c7543cceSMatthew G Knepley       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
3359566063dSJacob Faibussowitsch       PetscCall(KSPSetFromOptions(jac->kspschur));
336c7543cceSMatthew G Knepley 
3379566063dSJacob Faibussowitsch       PetscCall(PetscMalloc2(2,&jac->x,2,&jac->y));
3389566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(jac->pmat[0],&jac->x[0],&jac->y[0]));
3399566063dSJacob Faibussowitsch       PetscCall(MatCreateVecs(jac->pmat[1],&jac->x[1],&jac->y[1]));
340c7543cceSMatthew G Knepley       ilink    = jac->head;
341c7543cceSMatthew G Knepley       ilink->x = jac->x[0]; ilink->y = jac->y[0];
342c7543cceSMatthew G Knepley       ilink    = ilink->next;
343c7543cceSMatthew G Knepley       ilink->x = jac->x[1]; ilink->y = jac->y[1];
344c7543cceSMatthew G Knepley     }
345c7543cceSMatthew G Knepley #endif
346c7543cceSMatthew G Knepley   } else {
347c7543cceSMatthew G Knepley     /* Set up the individual SNESs */
348c7543cceSMatthew G Knepley     blocks = mb->blocks;
349c7543cceSMatthew G Knepley     i      = 0;
350c7543cceSMatthew G Knepley     while (blocks) {
351b665c654SMatthew G Knepley       /*TODO: Set these correctly */
3529566063dSJacob Faibussowitsch       /* PetscCall(SNESSetFunction(blocks->snes, blocks->x, func)); */
3539566063dSJacob Faibussowitsch       /* PetscCall(SNESSetJacobian(blocks->snes, blocks->x, jac)); */
3549566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(blocks->snes->vec_sol, &blocks->x));
355c7543cceSMatthew G Knepley       /* really want setfromoptions called in SNESSetFromOptions_Multiblock(), but it is not ready yet */
3569566063dSJacob Faibussowitsch       PetscCall(SNESSetFromOptions(blocks->snes));
3579566063dSJacob Faibussowitsch       PetscCall(SNESSetUp(blocks->snes));
358c7543cceSMatthew G Knepley       blocks = blocks->next;
359c7543cceSMatthew G Knepley       i++;
360c7543cceSMatthew G Knepley     }
361c7543cceSMatthew G Knepley   }
362c7543cceSMatthew G Knepley 
363c7543cceSMatthew G Knepley   /* Compute scatter contexts needed by multiplicative versions and non-default splits */
364c7543cceSMatthew G Knepley   if (!mb->blocks->sctx) {
365c7543cceSMatthew G Knepley     Vec xtmp;
366c7543cceSMatthew G Knepley 
367c7543cceSMatthew G Knepley     blocks = mb->blocks;
3689566063dSJacob Faibussowitsch     PetscCall(MatCreateVecs(snes->jacobian_pre, &xtmp, NULL));
369c7543cceSMatthew G Knepley     while (blocks) {
3709566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(xtmp, blocks->is, blocks->x, NULL, &blocks->sctx));
371c7543cceSMatthew G Knepley       blocks = blocks->next;
372c7543cceSMatthew G Knepley     }
3739566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&xtmp));
374c7543cceSMatthew G Knepley   }
3753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
376c7543cceSMatthew G Knepley }
377c7543cceSMatthew G Knepley 
378c7543cceSMatthew G Knepley /*
379c7543cceSMatthew G Knepley   SNESSetFromOptions_Multiblock - Sets various parameters for the SNESMULTIBLOCK method.
380c7543cceSMatthew G Knepley 
381c7543cceSMatthew G Knepley   Input Parameter:
382c7543cceSMatthew G Knepley . snes - the SNES context
383c7543cceSMatthew G Knepley 
384c7543cceSMatthew G Knepley   Application Interface Routine: SNESSetFromOptions()
385c7543cceSMatthew G Knepley */
SNESSetFromOptions_Multiblock(SNES snes,PetscOptionItems PetscOptionsObject)386ce78bad3SBarry Smith static PetscErrorCode SNESSetFromOptions_Multiblock(SNES snes, PetscOptionItems PetscOptionsObject)
387d71ae5a4SJacob Faibussowitsch {
388c7543cceSMatthew G Knepley   SNES_Multiblock *mb = (SNES_Multiblock *)snes->data;
389c7543cceSMatthew G Knepley   PCCompositeType  ctype;
390c7543cceSMatthew G Knepley   PetscInt         bs;
391c7543cceSMatthew G Knepley   PetscBool        flg;
392c7543cceSMatthew G Knepley 
393c7543cceSMatthew G Knepley   PetscFunctionBegin;
394d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "SNES Multiblock options");
3959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-snes_multiblock_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", mb->bs, &bs, &flg));
3969566063dSJacob Faibussowitsch   if (flg) PetscCall(SNESMultiblockSetBlockSize(snes, bs));
3979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-snes_multiblock_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum)mb->type, (PetscEnum *)&ctype, &flg));
3981baa6e33SBarry Smith   if (flg) PetscCall(SNESMultiblockSetType(snes, ctype));
399c7543cceSMatthew G Knepley   /* Only setup fields once */
400b665c654SMatthew G Knepley   if ((mb->bs > 0) && (mb->numBlocks == 0)) {
401c7543cceSMatthew G Knepley     /* only allow user to set fields from command line if bs is already known, otherwise user can set them in SNESMultiblockSetDefaults() */
4029566063dSJacob Faibussowitsch     PetscCall(SNESMultiblockSetFieldsRuntime_Private(snes));
4039566063dSJacob Faibussowitsch     if (mb->defined) PetscCall(PetscInfo(snes, "Blocks defined using the options database\n"));
404c7543cceSMatthew G Knepley   }
405d0609cedSBarry Smith   PetscOptionsHeadEnd();
4063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
407c7543cceSMatthew G Knepley }
408c7543cceSMatthew G Knepley 
SNESView_Multiblock(SNES snes,PetscViewer viewer)409d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESView_Multiblock(SNES snes, PetscViewer viewer)
410d71ae5a4SJacob Faibussowitsch {
411c7543cceSMatthew G Knepley   SNES_Multiblock *mb     = (SNES_Multiblock *)snes->data;
412c7543cceSMatthew G Knepley   BlockDesc        blocks = mb->blocks;
4139f196a02SMartin Diehl   PetscBool        isascii;
414c7543cceSMatthew G Knepley 
415c7543cceSMatthew G Knepley   PetscFunctionBegin;
4169f196a02SMartin Diehl   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
4179f196a02SMartin Diehl   if (isascii) {
41863a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Multiblock with %s composition: total blocks = %" PetscInt_FMT ", blocksize = %" PetscInt_FMT "\n", PCCompositeTypes[mb->type], mb->numBlocks, mb->bs));
4199566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Solver info for each split is in the following SNES objects:\n"));
4209566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
421c7543cceSMatthew G Knepley     while (blocks) {
422c7543cceSMatthew G Knepley       if (blocks->fields) {
423c7543cceSMatthew G Knepley         PetscInt j;
424c7543cceSMatthew G Knepley 
4259566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Block %s Fields ", blocks->name));
4269566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
427c7543cceSMatthew G Knepley         for (j = 0; j < blocks->nfields; ++j) {
42848a46eb9SPierre Jolivet           if (j > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ","));
42963a3b9bcSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT, blocks->fields[j]));
430c7543cceSMatthew G Knepley         }
4319566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
4329566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
433c7543cceSMatthew G Knepley       } else {
4349566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "  Block %s Defined by IS\n", blocks->name));
435c7543cceSMatthew G Knepley       }
4369566063dSJacob Faibussowitsch       PetscCall(SNESView(blocks->snes, viewer));
437c7543cceSMatthew G Knepley       blocks = blocks->next;
438c7543cceSMatthew G Knepley     }
4399566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
440c7543cceSMatthew G Knepley   }
4413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
442c7543cceSMatthew G Knepley }
443c7543cceSMatthew G Knepley 
SNESSolve_Multiblock(SNES snes)44466976f2fSJacob Faibussowitsch static PetscErrorCode SNESSolve_Multiblock(SNES snes)
445d71ae5a4SJacob Faibussowitsch {
446c7543cceSMatthew G Knepley   SNES_Multiblock *mb = (SNES_Multiblock *)snes->data;
447c7543cceSMatthew G Knepley   Vec              X, Y, F;
448c7543cceSMatthew G Knepley   PetscReal        fnorm;
449c7543cceSMatthew G Knepley   PetscInt         maxits, i;
450c7543cceSMatthew G Knepley 
451c7543cceSMatthew G Knepley   PetscFunctionBegin;
4520b121fc5SBarry Smith   PetscCheck(!snes->xl && !snes->xu && !snes->ops->computevariablebounds, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
453c579b300SPatrick Farrell 
454c7543cceSMatthew G Knepley   snes->reason = SNES_CONVERGED_ITERATING;
455c7543cceSMatthew G Knepley 
456c7543cceSMatthew G Knepley   maxits = snes->max_its;        /* maximum number of iterations */
457c7543cceSMatthew G Knepley   X      = snes->vec_sol;        /* X^n */
458c7543cceSMatthew G Knepley   Y      = snes->vec_sol_update; /* \tilde X */
459c7543cceSMatthew G Knepley   F      = snes->vec_func;       /* residual vector */
460c7543cceSMatthew G Knepley 
4619566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(X, mb->bs));
4629566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(Y, mb->bs));
4639566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(F, mb->bs));
4649566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
465c7543cceSMatthew G Knepley   snes->iter = 0;
466c7543cceSMatthew G Knepley   snes->norm = 0.;
4679566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
468e4ed7901SPeter Brune 
469ac530a7eSPierre Jolivet   if (!snes->vec_func_init_set) PetscCall(SNESComputeFunction(snes, X, F));
470ac530a7eSPierre Jolivet   else snes->vec_func_init_set = PETSC_FALSE;
4711aa26658SKarl Rupp 
4729566063dSJacob Faibussowitsch   PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- ||F||  */
473*76c63389SBarry Smith   SNESCheckFunctionDomainError(snes, fnorm);
4749566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
475c7543cceSMatthew G Knepley   snes->norm = fnorm;
4769566063dSJacob Faibussowitsch   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
4779566063dSJacob Faibussowitsch   PetscCall(SNESLogConvergenceHistory(snes, fnorm, 0));
478c7543cceSMatthew G Knepley 
479c7543cceSMatthew G Knepley   /* test convergence */
4802d157150SStefano Zampini   PetscCall(SNESConverged(snes, 0, 0.0, 0.0, fnorm));
4812d157150SStefano Zampini   PetscCall(SNESMonitor(snes, 0, fnorm));
4823ba16761SJacob Faibussowitsch   if (snes->reason) PetscFunctionReturn(PETSC_SUCCESS);
483c7543cceSMatthew G Knepley 
484c7543cceSMatthew G Knepley   for (i = 0; i < maxits; i++) {
485c7543cceSMatthew G Knepley     /* Call general purpose update function */
486dbbe0bcdSBarry Smith     PetscTryTypeMethod(snes, update, snes->iter);
487c7543cceSMatthew G Knepley     /* Compute X^{new} from subsolves */
488c7543cceSMatthew G Knepley     if (mb->type == PC_COMPOSITE_ADDITIVE) {
489c7543cceSMatthew G Knepley       BlockDesc blocks = mb->blocks;
490c7543cceSMatthew G Knepley 
491b665c654SMatthew G Knepley       if (mb->defaultblocks) {
492b665c654SMatthew G Knepley         /*TODO: Make an array of Vecs for this */
4939566063dSJacob Faibussowitsch         /* PetscCall(VecStrideGatherAll(X, mb->x, INSERT_VALUES)); */
494c7543cceSMatthew G Knepley         while (blocks) {
4959566063dSJacob Faibussowitsch           PetscCall(SNESSolve(blocks->snes, NULL, blocks->x));
496c7543cceSMatthew G Knepley           blocks = blocks->next;
497c7543cceSMatthew G Knepley         }
4989566063dSJacob Faibussowitsch         /* PetscCall(VecStrideScatterAll(mb->x, X, INSERT_VALUES)); */
499c7543cceSMatthew G Knepley       } else {
500c7543cceSMatthew G Knepley         while (blocks) {
5019566063dSJacob Faibussowitsch           PetscCall(VecScatterBegin(blocks->sctx, X, blocks->x, INSERT_VALUES, SCATTER_FORWARD));
5029566063dSJacob Faibussowitsch           PetscCall(VecScatterEnd(blocks->sctx, X, blocks->x, INSERT_VALUES, SCATTER_FORWARD));
5039566063dSJacob Faibussowitsch           PetscCall(SNESSolve(blocks->snes, NULL, blocks->x));
5049566063dSJacob Faibussowitsch           PetscCall(VecScatterBegin(blocks->sctx, blocks->x, X, INSERT_VALUES, SCATTER_REVERSE));
5059566063dSJacob Faibussowitsch           PetscCall(VecScatterEnd(blocks->sctx, blocks->x, X, INSERT_VALUES, SCATTER_REVERSE));
506c7543cceSMatthew G Knepley           blocks = blocks->next;
507c7543cceSMatthew G Knepley         }
508c7543cceSMatthew G Knepley       }
50963a3b9bcSJacob Faibussowitsch     } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "Unsupported or unknown composition %d", (int)mb->type);
510c7543cceSMatthew G Knepley     /* Compute F(X^{new}) */
5119566063dSJacob Faibussowitsch     PetscCall(SNESComputeFunction(snes, X, F));
5129566063dSJacob Faibussowitsch     PetscCall(VecNorm(F, NORM_2, &fnorm));
513*76c63389SBarry Smith     SNESCheckFunctionDomainError(snes, fnorm);
514c7543cceSMatthew G Knepley 
515e71169deSBarry Smith     if (snes->nfuncs >= snes->max_funcs && snes->max_funcs >= 0) {
516c7543cceSMatthew G Knepley       snes->reason = SNES_DIVERGED_FUNCTION_COUNT;
517c7543cceSMatthew G Knepley       break;
518c7543cceSMatthew G Knepley     }
519422a814eSBarry Smith 
520c7543cceSMatthew G Knepley     /* Monitor convergence */
5219566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
522c7543cceSMatthew G Knepley     snes->iter = i + 1;
523c7543cceSMatthew G Knepley     snes->norm = fnorm;
5249566063dSJacob Faibussowitsch     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
5259566063dSJacob Faibussowitsch     PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0));
526c7543cceSMatthew G Knepley     /* Test for convergence */
5272d157150SStefano Zampini     PetscCall(SNESConverged(snes, snes->iter, 0.0, 0.0, fnorm));
5282d157150SStefano Zampini     PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
529c7543cceSMatthew G Knepley     if (snes->reason) break;
530c7543cceSMatthew G Knepley   }
5313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
532c7543cceSMatthew G Knepley }
533c7543cceSMatthew G Knepley 
SNESMultiblockSetFields_Default(SNES snes,const char name[],PetscInt n,const PetscInt fields[])53466976f2fSJacob Faibussowitsch static PetscErrorCode SNESMultiblockSetFields_Default(SNES snes, const char name[], PetscInt n, const PetscInt fields[])
535d71ae5a4SJacob Faibussowitsch {
536c7543cceSMatthew G Knepley   SNES_Multiblock *mb = (SNES_Multiblock *)snes->data;
537c7543cceSMatthew G Knepley   BlockDesc        newblock, next = mb->blocks;
538c7543cceSMatthew G Knepley   char             prefix[128];
539c7543cceSMatthew G Knepley   PetscInt         i;
540c7543cceSMatthew G Knepley 
541c7543cceSMatthew G Knepley   PetscFunctionBegin;
542c7543cceSMatthew G Knepley   if (mb->defined) {
5439566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "Ignoring new block \"%s\" because the blocks have already been defined\n", name));
5443ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
545c7543cceSMatthew G Knepley   }
546c7543cceSMatthew G Knepley   for (i = 0; i < n; ++i) {
54763a3b9bcSJacob Faibussowitsch     PetscCheck(fields[i] < mb->bs, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " requested but only %" PetscInt_FMT " exist", fields[i], mb->bs);
54863a3b9bcSJacob Faibussowitsch     PetscCheck(fields[i] >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %" PetscInt_FMT " requested", fields[i]);
549c7543cceSMatthew G Knepley   }
5509566063dSJacob Faibussowitsch   PetscCall(PetscNew(&newblock));
551c7543cceSMatthew G Knepley   if (name) {
5529566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(name, &newblock->name));
553c7543cceSMatthew G Knepley   } else {
554c7543cceSMatthew G Knepley     PetscInt len = floor(log10(mb->numBlocks)) + 1;
555c7543cceSMatthew G Knepley 
5569566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len + 1, &newblock->name));
55763a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(newblock->name, len, "%" PetscInt_FMT, mb->numBlocks));
558c7543cceSMatthew G Knepley   }
559c7543cceSMatthew G Knepley   newblock->nfields = n;
5601aa26658SKarl Rupp 
5619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &newblock->fields));
5629566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(newblock->fields, fields, n));
5631aa26658SKarl Rupp 
5640298fd71SBarry Smith   newblock->next = NULL;
5651aa26658SKarl Rupp 
5669566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PetscObjectComm((PetscObject)snes), &newblock->snes));
5679566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)newblock->snes, (PetscObject)snes, 1));
5689566063dSJacob Faibussowitsch   PetscCall(SNESSetType(newblock->snes, SNESNRICHARDSON));
5699566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%smultiblock_%s_", ((PetscObject)snes)->prefix ? ((PetscObject)snes)->prefix : "", newblock->name));
5709566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(newblock->snes, prefix));
571c7543cceSMatthew G Knepley 
572c7543cceSMatthew G Knepley   if (!next) {
573c7543cceSMatthew G Knepley     mb->blocks         = newblock;
5740298fd71SBarry Smith     newblock->previous = NULL;
575c7543cceSMatthew G Knepley   } else {
576ad540459SPierre Jolivet     while (next->next) next = next->next;
577c7543cceSMatthew G Knepley     next->next         = newblock;
578c7543cceSMatthew G Knepley     newblock->previous = next;
579c7543cceSMatthew G Knepley   }
580c7543cceSMatthew G Knepley   mb->numBlocks++;
5813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
582c7543cceSMatthew G Knepley }
583c7543cceSMatthew G Knepley 
SNESMultiblockSetIS_Default(SNES snes,const char name[],IS is)58466976f2fSJacob Faibussowitsch static PetscErrorCode SNESMultiblockSetIS_Default(SNES snes, const char name[], IS is)
585d71ae5a4SJacob Faibussowitsch {
586c7543cceSMatthew G Knepley   SNES_Multiblock *mb = (SNES_Multiblock *)snes->data;
587c7543cceSMatthew G Knepley   BlockDesc        newblock, next = mb->blocks;
588c7543cceSMatthew G Knepley   char             prefix[128];
589c7543cceSMatthew G Knepley 
590c7543cceSMatthew G Knepley   PetscFunctionBegin;
591c7543cceSMatthew G Knepley   if (mb->defined) {
5929566063dSJacob Faibussowitsch     PetscCall(PetscInfo(snes, "Ignoring new block \"%s\" because the blocks have already been defined\n", name));
5933ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
594c7543cceSMatthew G Knepley   }
5959566063dSJacob Faibussowitsch   PetscCall(PetscNew(&newblock));
596c7543cceSMatthew G Knepley   if (name) {
5979566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(name, &newblock->name));
598c7543cceSMatthew G Knepley   } else {
599c7543cceSMatthew G Knepley     PetscInt len = floor(log10(mb->numBlocks)) + 1;
600c7543cceSMatthew G Knepley 
6019566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(len + 1, &newblock->name));
60263a3b9bcSJacob Faibussowitsch     PetscCall(PetscSNPrintf(newblock->name, len, "%" PetscInt_FMT, mb->numBlocks));
603c7543cceSMatthew G Knepley   }
604c7543cceSMatthew G Knepley   newblock->is = is;
6051aa26658SKarl Rupp 
6069566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)is));
6071aa26658SKarl Rupp 
6080298fd71SBarry Smith   newblock->next = NULL;
6091aa26658SKarl Rupp 
6109566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PetscObjectComm((PetscObject)snes), &newblock->snes));
6119566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)newblock->snes, (PetscObject)snes, 1));
6129566063dSJacob Faibussowitsch   PetscCall(SNESSetType(newblock->snes, SNESNRICHARDSON));
6139566063dSJacob Faibussowitsch   PetscCall(PetscSNPrintf(prefix, sizeof(prefix), "%smultiblock_%s_", ((PetscObject)snes)->prefix ? ((PetscObject)snes)->prefix : "", newblock->name));
6149566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(newblock->snes, prefix));
615c7543cceSMatthew G Knepley 
616c7543cceSMatthew G Knepley   if (!next) {
617c7543cceSMatthew G Knepley     mb->blocks         = newblock;
6180298fd71SBarry Smith     newblock->previous = NULL;
619c7543cceSMatthew G Knepley   } else {
620ad540459SPierre Jolivet     while (next->next) next = next->next;
621c7543cceSMatthew G Knepley     next->next         = newblock;
622c7543cceSMatthew G Knepley     newblock->previous = next;
623c7543cceSMatthew G Knepley   }
624c7543cceSMatthew G Knepley   mb->numBlocks++;
6253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
626c7543cceSMatthew G Knepley }
627c7543cceSMatthew G Knepley 
SNESMultiblockSetBlockSize_Default(SNES snes,PetscInt bs)62866976f2fSJacob Faibussowitsch static PetscErrorCode SNESMultiblockSetBlockSize_Default(SNES snes, PetscInt bs)
629d71ae5a4SJacob Faibussowitsch {
630c7543cceSMatthew G Knepley   SNES_Multiblock *mb = (SNES_Multiblock *)snes->data;
631c7543cceSMatthew G Knepley 
632c7543cceSMatthew G Knepley   PetscFunctionBegin;
63363a3b9bcSJacob Faibussowitsch   PetscCheck(bs >= 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %" PetscInt_FMT, bs);
6340b121fc5SBarry Smith   PetscCheck(mb->bs <= 0 || mb->bs == bs, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Cannot change blocksize from %" PetscInt_FMT " to %" PetscInt_FMT " after it has been set", mb->bs, bs);
635c7543cceSMatthew G Knepley   mb->bs = bs;
6363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
637c7543cceSMatthew G Knepley }
638c7543cceSMatthew G Knepley 
SNESMultiblockGetSubSNES_Default(SNES snes,PetscInt * n,SNES ** subsnes)63966976f2fSJacob Faibussowitsch static PetscErrorCode SNESMultiblockGetSubSNES_Default(SNES snes, PetscInt *n, SNES **subsnes)
640d71ae5a4SJacob Faibussowitsch {
641c7543cceSMatthew G Knepley   SNES_Multiblock *mb     = (SNES_Multiblock *)snes->data;
642c7543cceSMatthew G Knepley   BlockDesc        blocks = mb->blocks;
643c7543cceSMatthew G Knepley   PetscInt         cnt    = 0;
644c7543cceSMatthew G Knepley 
645c7543cceSMatthew G Knepley   PetscFunctionBegin;
6469566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mb->numBlocks, subsnes));
647c7543cceSMatthew G Knepley   while (blocks) {
648c7543cceSMatthew G Knepley     (*subsnes)[cnt++] = blocks->snes;
649c7543cceSMatthew G Knepley     blocks            = blocks->next;
650c7543cceSMatthew G Knepley   }
65163a3b9bcSJacob Faibussowitsch   PetscCheck(cnt == mb->numBlocks, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Corrupt SNESMULTIBLOCK object: number of blocks in linked list %" PetscInt_FMT " does not match number in object %" PetscInt_FMT, cnt, mb->numBlocks);
6521aa26658SKarl Rupp 
6531aa26658SKarl Rupp   if (n) *n = mb->numBlocks;
6543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
655c7543cceSMatthew G Knepley }
656c7543cceSMatthew G Knepley 
SNESMultiblockSetType_Default(SNES snes,PCCompositeType type)65766976f2fSJacob Faibussowitsch static PetscErrorCode SNESMultiblockSetType_Default(SNES snes, PCCompositeType type)
658d71ae5a4SJacob Faibussowitsch {
65987bd6022SMatthew G Knepley   SNES_Multiblock *mb = (SNES_Multiblock *)snes->data;
66087bd6022SMatthew G Knepley 
66187bd6022SMatthew G Knepley   PetscFunctionBegin;
66287bd6022SMatthew G Knepley   mb->type = type;
66387bd6022SMatthew G Knepley   if (type == PC_COMPOSITE_SCHUR) {
66487bd6022SMatthew G Knepley #if 1
66582f516ccSBarry Smith     SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "The Schur composite type is not yet supported");
66687bd6022SMatthew G Knepley #else
66787bd6022SMatthew G Knepley     snes->ops->solve = SNESSolve_Multiblock_Schur;
66887bd6022SMatthew G Knepley     snes->ops->view  = SNESView_Multiblock_Schur;
6691aa26658SKarl Rupp 
6709566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockGetSubSNES_C", SNESMultiblockGetSubSNES_Schur));
6719566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockSchurPrecondition_C", SNESMultiblockSchurPrecondition_Default));
67287bd6022SMatthew G Knepley #endif
67387bd6022SMatthew G Knepley   } else {
67487bd6022SMatthew G Knepley     snes->ops->solve = SNESSolve_Multiblock;
67587bd6022SMatthew G Knepley     snes->ops->view  = SNESView_Multiblock;
6761aa26658SKarl Rupp 
6779566063dSJacob Faibussowitsch     PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockGetSubSNES_C", SNESMultiblockGetSubSNES_Default));
67814e4dea2SJose E. Roman     PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockSchurPrecondition_C", NULL));
67987bd6022SMatthew G Knepley   }
6803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
68187bd6022SMatthew G Knepley }
68287bd6022SMatthew G Knepley 
683c7543cceSMatthew G Knepley /*@
684420bcc1bSBarry Smith   SNESMultiblockSetFields - Sets the fields for one particular block in a `SNESMULTIBLOCK` solver
685c7543cceSMatthew G Knepley 
686c3339decSBarry Smith   Logically Collective
687c7543cceSMatthew G Knepley 
688c7543cceSMatthew G Knepley   Input Parameters:
689c7543cceSMatthew G Knepley + snes   - the solver
690420bcc1bSBarry Smith . name   - name of this block, if `NULL` the number of the block is used
691c7543cceSMatthew G Knepley . n      - the number of fields in this block
692c7543cceSMatthew G Knepley - fields - the fields in this block
693c7543cceSMatthew G Knepley 
694c7543cceSMatthew G Knepley   Level: intermediate
695c7543cceSMatthew G Knepley 
69695452b02SPatrick Sanan   Notes:
697f6dfbefdSBarry Smith   Use `SNESMultiblockSetIS()` to set a completely general set of row indices as a block.
698c7543cceSMatthew G Knepley 
699f6dfbefdSBarry Smith   The `SNESMultiblockSetFields()` is for defining blocks as a group of strided indices, or fields.
700c7543cceSMatthew G Knepley   For example, if the vector block size is three then one can define a block as field 0, or
701c7543cceSMatthew G Knepley   1 or 2, or field 0,1 or 0,2 or 1,2 which means
70214c74629SNuno Nobre   0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x23x56x8.. x12x45x78x....
703c7543cceSMatthew G Knepley   where the numbered entries indicate what is in the block.
704c7543cceSMatthew G Knepley 
705c7543cceSMatthew G Knepley   This function is called once per block (it creates a new block each time). Solve options
706c7543cceSMatthew G Knepley   for this block will be available under the prefix -multiblock_BLOCKNAME_.
707c7543cceSMatthew G Knepley 
708420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESMULTIBLOCK`, `SNESMultiblockGetSubSNES()`, `SNESMultiblockSetBlockSize()`, `SNESMultiblockSetIS()`
709c7543cceSMatthew G Knepley @*/
SNESMultiblockSetFields(SNES snes,const char name[],PetscInt n,const PetscInt * fields)710d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMultiblockSetFields(SNES snes, const char name[], PetscInt n, const PetscInt *fields)
711d71ae5a4SJacob Faibussowitsch {
712c7543cceSMatthew G Knepley   PetscFunctionBegin;
713c7543cceSMatthew G Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
7144f572ea9SToby Isaac   PetscAssertPointer(name, 2);
71563a3b9bcSJacob Faibussowitsch   PetscCheck(n >= 1, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %" PetscInt_FMT " in split \"%s\" not positive", n, name);
7164f572ea9SToby Isaac   PetscAssertPointer(fields, 4);
717cac4c232SBarry Smith   PetscTryMethod(snes, "SNESMultiblockSetFields_C", (SNES, const char[], PetscInt, const PetscInt *), (snes, name, n, fields));
7183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
719c7543cceSMatthew G Knepley }
720c7543cceSMatthew G Knepley 
721c7543cceSMatthew G Knepley /*@
722420bcc1bSBarry Smith   SNESMultiblockSetIS - Sets the global row indices for one particular block in a `SNESMULTIBLOCK` solver
723c7543cceSMatthew G Knepley 
724c3339decSBarry Smith   Logically Collective
725c7543cceSMatthew G Knepley 
726c7543cceSMatthew G Knepley   Input Parameters:
727c7543cceSMatthew G Knepley + snes - the solver context
728420bcc1bSBarry Smith . name - name of this block, if `NULL` the number of the block is used
729c7543cceSMatthew G Knepley - is   - the index set that defines the global row indices in this block
730c7543cceSMatthew G Knepley 
7312fe279fdSBarry Smith   Level: intermediate
7322fe279fdSBarry Smith 
733c7543cceSMatthew G Knepley   Notes:
734f6dfbefdSBarry Smith   Use `SNESMultiblockSetFields()`, for blocks defined by strides.
735c7543cceSMatthew G Knepley 
736c7543cceSMatthew G Knepley   This function is called once per block (it creates a new block each time). Solve options
737c7543cceSMatthew G Knepley   for this block will be available under the prefix -multiblock_BLOCKNAME_.
738c7543cceSMatthew G Knepley 
739420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESMULTIBLOCK`, `SNESMultiblockGetSubSNES()`, `SNESMultiblockSetBlockSize()`, `SNESMultiblockSetFields()`
740c7543cceSMatthew G Knepley @*/
SNESMultiblockSetIS(SNES snes,const char name[],IS is)741d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMultiblockSetIS(SNES snes, const char name[], IS is)
742d71ae5a4SJacob Faibussowitsch {
743c7543cceSMatthew G Knepley   PetscFunctionBegin;
744c7543cceSMatthew G Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
7454f572ea9SToby Isaac   PetscAssertPointer(name, 2);
746c7543cceSMatthew G Knepley   PetscValidHeaderSpecific(is, IS_CLASSID, 3);
747cac4c232SBarry Smith   PetscTryMethod(snes, "SNESMultiblockSetIS_C", (SNES, const char[], IS), (snes, name, is));
7483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
749c7543cceSMatthew G Knepley }
750c7543cceSMatthew G Knepley 
751c7543cceSMatthew G Knepley /*@
752420bcc1bSBarry Smith   SNESMultiblockSetType - Sets the type of block combination used for a `SNESMULTIBLOCK` solver
753c7543cceSMatthew G Knepley 
754c3339decSBarry Smith   Logically Collective
755c7543cceSMatthew G Knepley 
756c7543cceSMatthew G Knepley   Input Parameters:
757c7543cceSMatthew G Knepley + snes - the solver context
758f6dfbefdSBarry Smith - type - `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE` (default), `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`
759c7543cceSMatthew G Knepley 
760c7543cceSMatthew G Knepley   Options Database Key:
761c7543cceSMatthew G Knepley . -snes_multiblock_type <type: one of multiplicative, additive, symmetric_multiplicative> - Sets block combination type
762c7543cceSMatthew G Knepley 
763f6dfbefdSBarry Smith   Level: advanced
764c7543cceSMatthew G Knepley 
765420bcc1bSBarry Smith   Developer Note:
766420bcc1bSBarry Smith   This `SNESType` uses `PCCompositeType`, while `SNESCompositeSetType()` uses `SNESCOMPOSITE`, perhaps they should be unified in the future
767420bcc1bSBarry Smith 
768420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESMULTIBLOCK`, `PCCompositeSetType()`, `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`,
769420bcc1bSBarry Smith           `PCCompositeType`, `SNESCOMPOSITE`, `SNESCompositeSetType()`
770c7543cceSMatthew G Knepley @*/
SNESMultiblockSetType(SNES snes,PCCompositeType type)771d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMultiblockSetType(SNES snes, PCCompositeType type)
772d71ae5a4SJacob Faibussowitsch {
773c7543cceSMatthew G Knepley   PetscFunctionBegin;
774c7543cceSMatthew G Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
775cac4c232SBarry Smith   PetscTryMethod(snes, "SNESMultiblockSetType_C", (SNES, PCCompositeType), (snes, type));
7763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
777c7543cceSMatthew G Knepley }
778c7543cceSMatthew G Knepley 
779c7543cceSMatthew G Knepley /*@
780420bcc1bSBarry Smith   SNESMultiblockSetBlockSize - Sets the block size for structured block division in a `SNESMULTIBLOCK` solver. If not set the matrix block size is used.
781c7543cceSMatthew G Knepley 
782c3339decSBarry Smith   Logically Collective
783c7543cceSMatthew G Knepley 
784c7543cceSMatthew G Knepley   Input Parameters:
785c7543cceSMatthew G Knepley + snes - the solver context
786c7543cceSMatthew G Knepley - bs   - the block size
787c7543cceSMatthew G Knepley 
788c7543cceSMatthew G Knepley   Level: intermediate
789c7543cceSMatthew G Knepley 
790420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESMULTIBLOCK`, `SNESMultiblockGetSubSNES()`, `SNESMultiblockSetFields()`
791c7543cceSMatthew G Knepley @*/
SNESMultiblockSetBlockSize(SNES snes,PetscInt bs)792d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMultiblockSetBlockSize(SNES snes, PetscInt bs)
793d71ae5a4SJacob Faibussowitsch {
794c7543cceSMatthew G Knepley   PetscFunctionBegin;
795c7543cceSMatthew G Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
796c7543cceSMatthew G Knepley   PetscValidLogicalCollectiveInt(snes, bs, 2);
797cac4c232SBarry Smith   PetscTryMethod(snes, "SNESMultiblockSetBlockSize_C", (SNES, PetscInt), (snes, bs));
7983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
799c7543cceSMatthew G Knepley }
800c7543cceSMatthew G Knepley 
801c7543cceSMatthew G Knepley /*@C
802420bcc1bSBarry Smith   SNESMultiblockGetSubSNES - Gets the `SNES` contexts for all blocks in a `SNESMULTIBLOCK` solver.
803c7543cceSMatthew G Knepley 
804f6dfbefdSBarry Smith   Not Collective but each `SNES` obtained is parallel
805c7543cceSMatthew G Knepley 
806c7543cceSMatthew G Knepley   Input Parameter:
807c7543cceSMatthew G Knepley . snes - the solver context
808c7543cceSMatthew G Knepley 
809c7543cceSMatthew G Knepley   Output Parameters:
810c7543cceSMatthew G Knepley + n       - the number of blocks
811f6dfbefdSBarry Smith - subsnes - the array of `SNES` contexts
812c7543cceSMatthew G Knepley 
8132fe279fdSBarry Smith   Level: advanced
8142fe279fdSBarry Smith 
815420bcc1bSBarry Smith   Notes:
816f6dfbefdSBarry Smith   After `SNESMultiblockGetSubSNES()` the array of `SNES`s MUST be freed by the user
817f6dfbefdSBarry Smith   (not each `SNES`, just the array that contains them).
818c7543cceSMatthew G Knepley 
819f6dfbefdSBarry Smith   You must call `SNESSetUp()` before calling `SNESMultiblockGetSubSNES()`.
820c7543cceSMatthew G Knepley 
821420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESMULTIBLOCK`, `SNESMultiblockSetIS()`, `SNESMultiblockSetFields()`
822c7543cceSMatthew G Knepley @*/
SNESMultiblockGetSubSNES(SNES snes,PetscInt * n,SNES * subsnes[])823d71ae5a4SJacob Faibussowitsch PetscErrorCode SNESMultiblockGetSubSNES(SNES snes, PetscInt *n, SNES *subsnes[])
824d71ae5a4SJacob Faibussowitsch {
825c7543cceSMatthew G Knepley   PetscFunctionBegin;
826c7543cceSMatthew G Knepley   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
8274f572ea9SToby Isaac   if (n) PetscAssertPointer(n, 2);
828cac4c232SBarry Smith   PetscUseMethod(snes, "SNESMultiblockGetSubSNES_C", (SNES, PetscInt *, SNES **), (snes, n, subsnes));
8293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
830c7543cceSMatthew G Knepley }
831c7543cceSMatthew G Knepley 
832c7543cceSMatthew G Knepley /*MC
833c7543cceSMatthew G Knepley   SNESMULTIBLOCK - Multiblock nonlinear solver that can use overlapping or nonoverlapping blocks, organized
834c7543cceSMatthew G Knepley   additively (Jacobi) or multiplicatively (Gauss-Seidel).
835c7543cceSMatthew G Knepley 
836c7543cceSMatthew G Knepley   Level: beginner
837c7543cceSMatthew G Knepley 
838420bcc1bSBarry Smith   Note:
839420bcc1bSBarry Smith   This is much like  `PCASM`, `PCBJACOBI`, and `PCFIELDSPLIT` are for linear problems.
840420bcc1bSBarry Smith 
841420bcc1bSBarry Smith .seealso: [](ch_snes), `SNES`, `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESNEWTONLS`, `SNESNEWTONTR`, `SNESNRICHARDSON`, `SNESMultiblockSetType()`,
842420bcc1bSBarry Smith           `PC_COMPOSITE_ADDITIVE`, `PC_COMPOSITE_MULTIPLICATIVE`, `PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE`, `SNESMultiblockSetBlockSize()`,
843420bcc1bSBarry Smith           `SNESMultiblockGetBlockSize()`, `SNESMultiblockSetFields()`, `SNESMultiblockSetIS()`, `SNESMultiblockGetSubSNES()`, `PCASM`, `PCBJACOBI`
844c7543cceSMatthew G Knepley M*/
SNESCreate_Multiblock(SNES snes)845d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode SNESCreate_Multiblock(SNES snes)
846d71ae5a4SJacob Faibussowitsch {
847c7543cceSMatthew G Knepley   SNES_Multiblock *mb;
848c7543cceSMatthew G Knepley 
849c7543cceSMatthew G Knepley   PetscFunctionBegin;
850c7543cceSMatthew G Knepley   snes->ops->destroy        = SNESDestroy_Multiblock;
851c7543cceSMatthew G Knepley   snes->ops->setup          = SNESSetUp_Multiblock;
852c7543cceSMatthew G Knepley   snes->ops->setfromoptions = SNESSetFromOptions_Multiblock;
853c7543cceSMatthew G Knepley   snes->ops->view           = SNESView_Multiblock;
854c7543cceSMatthew G Knepley   snes->ops->solve          = SNESSolve_Multiblock;
855c7543cceSMatthew G Knepley   snes->ops->reset          = SNESReset_Multiblock;
856c7543cceSMatthew G Knepley 
8572c155ee1SBarry Smith   snes->usesksp = PETSC_FALSE;
858d8d34be6SBarry Smith   snes->usesnpc = PETSC_FALSE;
8592c155ee1SBarry Smith 
8604fc747eaSLawrence Mitchell   snes->alwayscomputesfinalresidual = PETSC_TRUE;
8614fc747eaSLawrence Mitchell 
86277e5a1f9SBarry Smith   PetscCall(SNESParametersInitialize(snes));
86377e5a1f9SBarry Smith 
8644dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&mb));
865c7543cceSMatthew G Knepley   snes->data    = (void *)mb;
866c7543cceSMatthew G Knepley   mb->defined   = PETSC_FALSE;
867c7543cceSMatthew G Knepley   mb->numBlocks = 0;
868c7543cceSMatthew G Knepley   mb->bs        = -1;
869c7543cceSMatthew G Knepley   mb->type      = PC_COMPOSITE_MULTIPLICATIVE;
870c7543cceSMatthew G Knepley 
871c7543cceSMatthew G Knepley   /* We attach functions so that they can be called on another PC without crashing the program */
8729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockSetFields_C", SNESMultiblockSetFields_Default));
8739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockSetIS_C", SNESMultiblockSetIS_Default));
8749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockSetType_C", SNESMultiblockSetType_Default));
8759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockSetBlockSize_C", SNESMultiblockSetBlockSize_Default));
8769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESMultiblockGetSubSNES_C", SNESMultiblockGetSubSNES_Default));
8773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
878c7543cceSMatthew G Knepley }
879