xref: /petsc/src/snes/impls/nasm/nasm.c (revision a69119a591a03a9d906b29c0a4e9802e4d7c9795)
1 #include <petsc/private/snesimpl.h> /*I   "petscsnes.h"   I*/
2 #include <petscdm.h>
3 
4 typedef struct {
5   PetscInt    n;             /* local subdomains */
6   SNES       *subsnes;       /* nonlinear solvers for each subdomain */
7   Vec        *x;             /* solution vectors */
8   Vec        *xl;            /* solution local vectors */
9   Vec        *y;             /* step vectors */
10   Vec        *b;             /* rhs vectors */
11   Vec         weight;        /* weighting for adding updates on overlaps, in global space */
12   VecScatter *oscatter;      /* scatter from global space to the subdomain global space */
13   VecScatter *oscatter_copy; /* copy of the above */
14   VecScatter *iscatter;      /* scatter from global space to the nonoverlapping subdomain space */
15   VecScatter *gscatter;      /* scatter from global space to the subdomain local space */
16   PCASMType   type;          /* ASM type */
17   PetscBool   usesdm;        /* use the DM for setting up the subproblems */
18   PetscBool   finaljacobian; /* compute the jacobian of the converged solution */
19   PetscReal   damping;       /* damping parameter for updates from the blocks */
20   PetscBool   weight_set;    /* use a weight in the overlap updates */
21 
22   /* logging events */
23   PetscLogEvent eventrestrictinterp;
24   PetscLogEvent eventsubsolve;
25 
26   PetscInt fjtype; /* type of computed jacobian */
27   Vec      xinit;  /* initial solution in case the final jacobian type is computed as first */
28 } SNES_NASM;
29 
30 const char *const SNESNASMTypes[]   = {"NONE", "RESTRICT", "INTERPOLATE", "BASIC", "PCASMType", "PC_ASM_", NULL};
31 const char *const SNESNASMFJTypes[] = {"FINALOUTER", "FINALINNER", "INITIAL"};
32 
33 static PetscErrorCode SNESReset_NASM(SNES snes) {
34   SNES_NASM *nasm = (SNES_NASM *)snes->data;
35   PetscInt   i;
36 
37   PetscFunctionBegin;
38   for (i = 0; i < nasm->n; i++) {
39     if (nasm->xl) PetscCall(VecDestroy(&nasm->xl[i]));
40     if (nasm->x) PetscCall(VecDestroy(&nasm->x[i]));
41     if (nasm->y) PetscCall(VecDestroy(&nasm->y[i]));
42     if (nasm->b) PetscCall(VecDestroy(&nasm->b[i]));
43 
44     if (nasm->subsnes) PetscCall(SNESDestroy(&nasm->subsnes[i]));
45     if (nasm->oscatter) PetscCall(VecScatterDestroy(&nasm->oscatter[i]));
46     if (nasm->oscatter_copy) PetscCall(VecScatterDestroy(&nasm->oscatter_copy[i]));
47     if (nasm->iscatter) PetscCall(VecScatterDestroy(&nasm->iscatter[i]));
48     if (nasm->gscatter) PetscCall(VecScatterDestroy(&nasm->gscatter[i]));
49   }
50 
51   PetscCall(PetscFree(nasm->x));
52   PetscCall(PetscFree(nasm->xl));
53   PetscCall(PetscFree(nasm->y));
54   PetscCall(PetscFree(nasm->b));
55 
56   if (nasm->xinit) PetscCall(VecDestroy(&nasm->xinit));
57 
58   PetscCall(PetscFree(nasm->subsnes));
59   PetscCall(PetscFree(nasm->oscatter));
60   PetscCall(PetscFree(nasm->oscatter_copy));
61   PetscCall(PetscFree(nasm->iscatter));
62   PetscCall(PetscFree(nasm->gscatter));
63 
64   if (nasm->weight_set) PetscCall(VecDestroy(&nasm->weight));
65 
66   nasm->eventrestrictinterp = 0;
67   nasm->eventsubsolve       = 0;
68   PetscFunctionReturn(0);
69 }
70 
71 static PetscErrorCode SNESDestroy_NASM(SNES snes) {
72   PetscFunctionBegin;
73   PetscCall(SNESReset_NASM(snes));
74   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetType_C", NULL));
75   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetType_C", NULL));
76   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetSubdomains_C", NULL));
77   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetSubdomains_C", NULL));
78   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetDamping_C", NULL));
79   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetDamping_C", NULL));
80   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetSubdomainVecs_C", NULL));
81   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetComputeFinalJacobian_C", NULL));
82   PetscCall(PetscFree(snes->data));
83   PetscFunctionReturn(0);
84 }
85 
86 static PetscErrorCode DMGlobalToLocalSubDomainDirichletHook_Private(DM dm, Vec g, InsertMode mode, Vec l, void *ctx) {
87   Vec bcs = (Vec)ctx;
88 
89   PetscFunctionBegin;
90   PetscCall(VecCopy(bcs, l));
91   PetscFunctionReturn(0);
92 }
93 
94 static PetscErrorCode SNESSetUp_NASM(SNES snes) {
95   SNES_NASM  *nasm = (SNES_NASM *)snes->data;
96   DM          dm, subdm;
97   DM         *subdms;
98   PetscInt    i;
99   const char *optionsprefix;
100   Vec         F;
101   PetscMPIInt size;
102   KSP         ksp;
103   PC          pc;
104 
105   PetscFunctionBegin;
106   if (!nasm->subsnes) {
107     PetscCall(SNESGetDM(snes, &dm));
108     if (dm) {
109       nasm->usesdm = PETSC_TRUE;
110       PetscCall(DMCreateDomainDecomposition(dm, &nasm->n, NULL, NULL, NULL, &subdms));
111       PetscCheck(subdms, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM has no default decomposition defined.  Set subsolves manually with SNESNASMSetSubdomains().");
112       PetscCall(DMCreateDomainDecompositionScatters(dm, nasm->n, subdms, &nasm->iscatter, &nasm->oscatter, &nasm->gscatter));
113       PetscCall(PetscMalloc1(nasm->n, &nasm->oscatter_copy));
114       for (i = 0; i < nasm->n; i++) PetscCall(VecScatterCopy(nasm->oscatter[i], &nasm->oscatter_copy[i]));
115 
116       PetscCall(SNESGetOptionsPrefix(snes, &optionsprefix));
117       PetscCall(PetscMalloc1(nasm->n, &nasm->subsnes));
118       for (i = 0; i < nasm->n; i++) {
119         PetscCall(SNESCreate(PETSC_COMM_SELF, &nasm->subsnes[i]));
120         PetscCall(PetscObjectIncrementTabLevel((PetscObject)nasm->subsnes[i], (PetscObject)snes, 1));
121         PetscCall(SNESAppendOptionsPrefix(nasm->subsnes[i], optionsprefix));
122         PetscCall(SNESAppendOptionsPrefix(nasm->subsnes[i], "sub_"));
123         PetscCall(SNESSetDM(nasm->subsnes[i], subdms[i]));
124         PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)nasm->subsnes[i]), &size));
125         if (size == 1) {
126           PetscCall(SNESGetKSP(nasm->subsnes[i], &ksp));
127           PetscCall(KSPGetPC(ksp, &pc));
128           PetscCall(KSPSetType(ksp, KSPPREONLY));
129           PetscCall(PCSetType(pc, PCLU));
130         }
131         PetscCall(SNESSetFromOptions(nasm->subsnes[i]));
132         PetscCall(DMDestroy(&subdms[i]));
133       }
134       PetscCall(PetscFree(subdms));
135     } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Cannot construct local problems automatically without a DM!");
136   } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Must set subproblems manually if there is no DM!");
137   /* allocate the global vectors */
138   if (!nasm->x) PetscCall(PetscCalloc1(nasm->n, &nasm->x));
139   if (!nasm->xl) PetscCall(PetscCalloc1(nasm->n, &nasm->xl));
140   if (!nasm->y) PetscCall(PetscCalloc1(nasm->n, &nasm->y));
141   if (!nasm->b) PetscCall(PetscCalloc1(nasm->n, &nasm->b));
142 
143   for (i = 0; i < nasm->n; i++) {
144     PetscCall(SNESGetFunction(nasm->subsnes[i], &F, NULL, NULL));
145     if (!nasm->x[i]) PetscCall(VecDuplicate(F, &nasm->x[i]));
146     if (!nasm->y[i]) PetscCall(VecDuplicate(F, &nasm->y[i]));
147     if (!nasm->b[i]) PetscCall(VecDuplicate(F, &nasm->b[i]));
148     if (!nasm->xl[i]) {
149       PetscCall(SNESGetDM(nasm->subsnes[i], &subdm));
150       PetscCall(DMCreateLocalVector(subdm, &nasm->xl[i]));
151       PetscCall(DMGlobalToLocalHookAdd(subdm, DMGlobalToLocalSubDomainDirichletHook_Private, NULL, nasm->xl[i]));
152     }
153   }
154   if (nasm->finaljacobian) {
155     PetscCall(SNESSetUpMatrices(snes));
156     if (nasm->fjtype == 2) PetscCall(VecDuplicate(snes->vec_sol, &nasm->xinit));
157     for (i = 0; i < nasm->n; i++) PetscCall(SNESSetUpMatrices(nasm->subsnes[i]));
158   }
159   PetscFunctionReturn(0);
160 }
161 
162 static PetscErrorCode SNESSetFromOptions_NASM(SNES snes, PetscOptionItems *PetscOptionsObject) {
163   PCASMType  asmtype;
164   PetscBool  flg, monflg;
165   SNES_NASM *nasm = (SNES_NASM *)snes->data;
166 
167   PetscFunctionBegin;
168   PetscOptionsHeadBegin(PetscOptionsObject, "Nonlinear Additive Schwarz options");
169   PetscCall(PetscOptionsEnum("-snes_nasm_type", "Type of restriction/extension", "", SNESNASMTypes, (PetscEnum)nasm->type, (PetscEnum *)&asmtype, &flg));
170   if (flg) PetscCall(SNESNASMSetType(snes, asmtype));
171   flg    = PETSC_FALSE;
172   monflg = PETSC_TRUE;
173   PetscCall(PetscOptionsReal("-snes_nasm_damping", "The new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains)", "SNESNASMSetDamping", nasm->damping, &nasm->damping, &flg));
174   if (flg) PetscCall(SNESNASMSetDamping(snes, nasm->damping));
175   PetscCall(PetscOptionsDeprecated("-snes_nasm_sub_view", NULL, "3.15", "Use -snes_view ::ascii_info_detail"));
176   PetscCall(PetscOptionsBool("-snes_nasm_finaljacobian", "Compute the global jacobian of the final iterate (for ASPIN)", "", nasm->finaljacobian, &nasm->finaljacobian, NULL));
177   PetscCall(PetscOptionsEList("-snes_nasm_finaljacobian_type", "The type of the final jacobian computed.", "", SNESNASMFJTypes, 3, SNESNASMFJTypes[0], &nasm->fjtype, NULL));
178   PetscCall(PetscOptionsBool("-snes_nasm_log", "Log times for subSNES solves and restriction", "", monflg, &monflg, &flg));
179   if (flg) {
180     PetscCall(PetscLogEventRegister("SNESNASMSubSolve", ((PetscObject)snes)->classid, &nasm->eventsubsolve));
181     PetscCall(PetscLogEventRegister("SNESNASMRestrict", ((PetscObject)snes)->classid, &nasm->eventrestrictinterp));
182   }
183   PetscOptionsHeadEnd();
184   PetscFunctionReturn(0);
185 }
186 
187 static PetscErrorCode SNESView_NASM(SNES snes, PetscViewer viewer) {
188   SNES_NASM        *nasm = (SNES_NASM *)snes->data;
189   PetscMPIInt       rank, size;
190   PetscInt          i, N, bsz;
191   PetscBool         iascii, isstring;
192   PetscViewer       sviewer;
193   MPI_Comm          comm;
194   PetscViewerFormat format;
195   const char       *prefix;
196 
197   PetscFunctionBegin;
198   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
199   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
200   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERSTRING, &isstring));
201   PetscCallMPI(MPI_Comm_rank(comm, &rank));
202   PetscCallMPI(MPI_Comm_size(comm, &size));
203   PetscCall(MPIU_Allreduce(&nasm->n, &N, 1, MPIU_INT, MPI_SUM, comm));
204   if (iascii) {
205     PetscCall(PetscViewerASCIIPrintf(viewer, "  total subdomain blocks = %" PetscInt_FMT "\n", N));
206     PetscCall(PetscViewerGetFormat(viewer, &format));
207     if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) {
208       if (nasm->subsnes) {
209         PetscCall(PetscViewerASCIIPrintf(viewer, "  Local solver information for first block on rank 0:\n"));
210         PetscCall(SNESGetOptionsPrefix(snes, &prefix));
211         PetscCall(PetscViewerASCIIPrintf(viewer, "  Use -%ssnes_view ::ascii_info_detail to display information for all blocks\n", prefix ? prefix : ""));
212         PetscCall(PetscViewerASCIIPushTab(viewer));
213         PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
214         if (rank == 0) {
215           PetscCall(PetscViewerASCIIPushTab(viewer));
216           PetscCall(SNESView(nasm->subsnes[0], sviewer));
217           PetscCall(PetscViewerASCIIPopTab(viewer));
218         }
219         PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
220         PetscCall(PetscViewerASCIIPopTab(viewer));
221       }
222     } else {
223       /* print the solver on each block */
224       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
225       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  [%d] number of local blocks = %" PetscInt_FMT "\n", (int)rank, nasm->n));
226       PetscCall(PetscViewerFlush(viewer));
227       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
228       PetscCall(PetscViewerASCIIPrintf(viewer, "  Local solver information for each block is in the following SNES objects:\n"));
229       PetscCall(PetscViewerASCIIPushTab(viewer));
230       PetscCall(PetscViewerASCIIPrintf(viewer, "- - - - - - - - - - - - - - - - - -\n"));
231       PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
232       for (i = 0; i < nasm->n; i++) {
233         PetscCall(VecGetLocalSize(nasm->x[i], &bsz));
234         PetscCall(PetscViewerASCIIPrintf(sviewer, "[%d] local block number %" PetscInt_FMT ", size = %" PetscInt_FMT "\n", (int)rank, i, bsz));
235         PetscCall(SNESView(nasm->subsnes[i], sviewer));
236         PetscCall(PetscViewerASCIIPrintf(sviewer, "- - - - - - - - - - - - - - - - - -\n"));
237       }
238       PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
239       PetscCall(PetscViewerFlush(viewer));
240       PetscCall(PetscViewerASCIIPopTab(viewer));
241     }
242   } else if (isstring) {
243     PetscCall(PetscViewerStringSPrintf(viewer, " blocks=%" PetscInt_FMT ",type=%s", N, SNESNASMTypes[nasm->type]));
244     PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
245     if (nasm->subsnes && rank == 0) PetscCall(SNESView(nasm->subsnes[0], sviewer));
246     PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer));
247   }
248   PetscFunctionReturn(0);
249 }
250 
251 /*@
252    SNESNASMSetType - Set the type of subdomain update used
253 
254    Logically Collective on SNES
255 
256    Input Parameters:
257 +  SNES - the SNES context
258 -  type - the type of update, PC_ASM_BASIC or PC_ASM_RESTRICT
259 
260    Level: intermediate
261 
262 .seealso: `SNESNASM`, `SNESNASMGetType()`, `PCASMSetType()`
263 @*/
264 PetscErrorCode SNESNASMSetType(SNES snes, PCASMType type) {
265   PetscErrorCode (*f)(SNES, PCASMType);
266 
267   PetscFunctionBegin;
268   PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetType_C", &f));
269   if (f) PetscCall((f)(snes, type));
270   PetscFunctionReturn(0);
271 }
272 
273 static PetscErrorCode SNESNASMSetType_NASM(SNES snes, PCASMType type) {
274   SNES_NASM *nasm = (SNES_NASM *)snes->data;
275 
276   PetscFunctionBegin;
277   PetscCheck(type == PC_ASM_BASIC || type == PC_ASM_RESTRICT, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "SNESNASM only supports basic and restrict types");
278   nasm->type = type;
279   PetscFunctionReturn(0);
280 }
281 
282 /*@
283    SNESNASMGetType - Get the type of subdomain update used
284 
285    Logically Collective on SNES
286 
287    Input Parameters:
288 .  SNES - the SNES context
289 
290    Output Parameters:
291 .  type - the type of update
292 
293    Level: intermediate
294 
295 .seealso: `SNESNASM`, `SNESNASMSetType()`, `PCASMGetType()`
296 @*/
297 PetscErrorCode SNESNASMGetType(SNES snes, PCASMType *type) {
298   PetscFunctionBegin;
299   PetscUseMethod(snes, "SNESNASMGetType_C", (SNES, PCASMType *), (snes, type));
300   PetscFunctionReturn(0);
301 }
302 
303 static PetscErrorCode SNESNASMGetType_NASM(SNES snes, PCASMType *type) {
304   SNES_NASM *nasm = (SNES_NASM *)snes->data;
305 
306   PetscFunctionBegin;
307   *type = nasm->type;
308   PetscFunctionReturn(0);
309 }
310 
311 /*@
312    SNESNASMSetSubdomains - Manually Set the context required to restrict and solve subdomain problems.
313 
314    Not Collective
315 
316    Input Parameters:
317 +  SNES - the SNES context
318 .  n - the number of local subdomains
319 .  subsnes - solvers defined on the local subdomains
320 .  iscatter - scatters into the nonoverlapping portions of the local subdomains
321 .  oscatter - scatters into the overlapping portions of the local subdomains
322 -  gscatter - scatters into the (ghosted) local vector of the local subdomain
323 
324    Level: intermediate
325 
326 .seealso: `SNESNASM`, `SNESNASMGetSubdomains()`
327 @*/
328 PetscErrorCode SNESNASMSetSubdomains(SNES snes, PetscInt n, SNES subsnes[], VecScatter iscatter[], VecScatter oscatter[], VecScatter gscatter[]) {
329   PetscErrorCode (*f)(SNES, PetscInt, SNES *, VecScatter *, VecScatter *, VecScatter *);
330 
331   PetscFunctionBegin;
332   PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetSubdomains_C", &f));
333   if (f) PetscCall((f)(snes, n, subsnes, iscatter, oscatter, gscatter));
334   PetscFunctionReturn(0);
335 }
336 
337 static PetscErrorCode SNESNASMSetSubdomains_NASM(SNES snes, PetscInt n, SNES subsnes[], VecScatter iscatter[], VecScatter oscatter[], VecScatter gscatter[]) {
338   PetscInt   i;
339   SNES_NASM *nasm = (SNES_NASM *)snes->data;
340 
341   PetscFunctionBegin;
342   PetscCheck(!snes->setupcalled, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNESNASMSetSubdomains() should be called before calling SNESSetUp().");
343 
344   /* tear down the previously set things */
345   PetscCall(SNESReset(snes));
346 
347   nasm->n = n;
348   if (oscatter) {
349     for (i = 0; i < n; i++) PetscCall(PetscObjectReference((PetscObject)oscatter[i]));
350   }
351   if (iscatter) {
352     for (i = 0; i < n; i++) PetscCall(PetscObjectReference((PetscObject)iscatter[i]));
353   }
354   if (gscatter) {
355     for (i = 0; i < n; i++) PetscCall(PetscObjectReference((PetscObject)gscatter[i]));
356   }
357   if (oscatter) {
358     PetscCall(PetscMalloc1(n, &nasm->oscatter));
359     PetscCall(PetscMalloc1(n, &nasm->oscatter_copy));
360     for (i = 0; i < n; i++) {
361       nasm->oscatter[i] = oscatter[i];
362       PetscCall(VecScatterCopy(oscatter[i], &nasm->oscatter_copy[i]));
363     }
364   }
365   if (iscatter) {
366     PetscCall(PetscMalloc1(n, &nasm->iscatter));
367     for (i = 0; i < n; i++) nasm->iscatter[i] = iscatter[i];
368   }
369   if (gscatter) {
370     PetscCall(PetscMalloc1(n, &nasm->gscatter));
371     for (i = 0; i < n; i++) nasm->gscatter[i] = gscatter[i];
372   }
373 
374   if (subsnes) {
375     PetscCall(PetscMalloc1(n, &nasm->subsnes));
376     for (i = 0; i < n; i++) nasm->subsnes[i] = subsnes[i];
377   }
378   PetscFunctionReturn(0);
379 }
380 
381 /*@
382    SNESNASMGetSubdomains - Get the local subdomain context.
383 
384    Not Collective
385 
386    Input Parameter:
387 .  SNES - the SNES context
388 
389    Output Parameters:
390 +  n - the number of local subdomains
391 .  subsnes - solvers defined on the local subdomains
392 .  iscatter - scatters into the nonoverlapping portions of the local subdomains
393 .  oscatter - scatters into the overlapping portions of the local subdomains
394 -  gscatter - scatters into the (ghosted) local vector of the local subdomain
395 
396    Level: intermediate
397 
398 .seealso: `SNESNASM`, `SNESNASMSetSubdomains()`
399 @*/
400 PetscErrorCode SNESNASMGetSubdomains(SNES snes, PetscInt *n, SNES *subsnes[], VecScatter *iscatter[], VecScatter *oscatter[], VecScatter *gscatter[]) {
401   PetscErrorCode (*f)(SNES, PetscInt *, SNES **, VecScatter **, VecScatter **, VecScatter **);
402 
403   PetscFunctionBegin;
404   PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMGetSubdomains_C", &f));
405   if (f) PetscCall((f)(snes, n, subsnes, iscatter, oscatter, gscatter));
406   PetscFunctionReturn(0);
407 }
408 
409 static PetscErrorCode SNESNASMGetSubdomains_NASM(SNES snes, PetscInt *n, SNES *subsnes[], VecScatter *iscatter[], VecScatter *oscatter[], VecScatter *gscatter[]) {
410   SNES_NASM *nasm = (SNES_NASM *)snes->data;
411 
412   PetscFunctionBegin;
413   if (n) *n = nasm->n;
414   if (oscatter) *oscatter = nasm->oscatter;
415   if (iscatter) *iscatter = nasm->iscatter;
416   if (gscatter) *gscatter = nasm->gscatter;
417   if (subsnes) *subsnes = nasm->subsnes;
418   PetscFunctionReturn(0);
419 }
420 
421 /*@
422    SNESNASMGetSubdomainVecs - Get the processor-local subdomain vectors
423 
424    Not Collective
425 
426    Input Parameter:
427 .  SNES - the SNES context
428 
429    Output Parameters:
430 +  n - the number of local subdomains
431 .  x - The subdomain solution vector
432 .  y - The subdomain step vector
433 .  b - The subdomain RHS vector
434 -  xl - The subdomain local vectors (ghosted)
435 
436    Level: developer
437 
438 .seealso: `SNESNASM`, `SNESNASMGetSubdomains()`
439 @*/
440 PetscErrorCode SNESNASMGetSubdomainVecs(SNES snes, PetscInt *n, Vec **x, Vec **y, Vec **b, Vec **xl) {
441   PetscErrorCode (*f)(SNES, PetscInt *, Vec **, Vec **, Vec **, Vec **);
442 
443   PetscFunctionBegin;
444   PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMGetSubdomainVecs_C", &f));
445   if (f) PetscCall((f)(snes, n, x, y, b, xl));
446   PetscFunctionReturn(0);
447 }
448 
449 static PetscErrorCode SNESNASMGetSubdomainVecs_NASM(SNES snes, PetscInt *n, Vec **x, Vec **y, Vec **b, Vec **xl) {
450   SNES_NASM *nasm = (SNES_NASM *)snes->data;
451 
452   PetscFunctionBegin;
453   if (n) *n = nasm->n;
454   if (x) *x = nasm->x;
455   if (y) *y = nasm->y;
456   if (b) *b = nasm->b;
457   if (xl) *xl = nasm->xl;
458   PetscFunctionReturn(0);
459 }
460 
461 /*@
462    SNESNASMSetComputeFinalJacobian - Schedules the computation of the global and subdomain Jacobians upon convergence
463 
464    Collective on SNES
465 
466    Input Parameters:
467 +  SNES - the SNES context
468 -  flg - indication of whether to compute the Jacobians or not
469 
470    Level: developer
471 
472    Notes:
473    This is used almost exclusively in the implementation of ASPIN, where the converged subdomain and global Jacobian
474    is needed at each linear iteration.
475 
476 .seealso: `SNESNASM`, `SNESNASMGetSubdomains()`
477 @*/
478 PetscErrorCode SNESNASMSetComputeFinalJacobian(SNES snes, PetscBool flg) {
479   PetscErrorCode (*f)(SNES, PetscBool);
480 
481   PetscFunctionBegin;
482   PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetComputeFinalJacobian_C", &f));
483   if (f) PetscCall((f)(snes, flg));
484   PetscFunctionReturn(0);
485 }
486 
487 static PetscErrorCode SNESNASMSetComputeFinalJacobian_NASM(SNES snes, PetscBool flg) {
488   SNES_NASM *nasm = (SNES_NASM *)snes->data;
489 
490   PetscFunctionBegin;
491   nasm->finaljacobian = flg;
492   PetscFunctionReturn(0);
493 }
494 
495 /*@
496    SNESNASMSetDamping - Sets the update damping for NASM
497 
498    Logically collective on SNES
499 
500    Input Parameters:
501 +  SNES - the SNES context
502 -  dmp - damping
503 
504    Level: intermediate
505 
506    Notes:
507     The new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains)
508 
509 .seealso: `SNESNASM`, `SNESNASMGetDamping()`
510 @*/
511 PetscErrorCode SNESNASMSetDamping(SNES snes, PetscReal dmp) {
512   PetscErrorCode (*f)(SNES, PetscReal);
513 
514   PetscFunctionBegin;
515   PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetDamping_C", (void (**)(void)) & f));
516   if (f) PetscCall((f)(snes, dmp));
517   PetscFunctionReturn(0);
518 }
519 
520 static PetscErrorCode SNESNASMSetDamping_NASM(SNES snes, PetscReal dmp) {
521   SNES_NASM *nasm = (SNES_NASM *)snes->data;
522 
523   PetscFunctionBegin;
524   nasm->damping = dmp;
525   PetscFunctionReturn(0);
526 }
527 
528 /*@
529    SNESNASMGetDamping - Gets the update damping for NASM
530 
531    Not Collective
532 
533    Input Parameters:
534 +  SNES - the SNES context
535 -  dmp - damping
536 
537    Level: intermediate
538 
539 .seealso: `SNESNASM`, `SNESNASMSetDamping()`
540 @*/
541 PetscErrorCode SNESNASMGetDamping(SNES snes, PetscReal *dmp) {
542   PetscFunctionBegin;
543   PetscUseMethod(snes, "SNESNASMGetDamping_C", (SNES, PetscReal *), (snes, dmp));
544   PetscFunctionReturn(0);
545 }
546 
547 static PetscErrorCode SNESNASMGetDamping_NASM(SNES snes, PetscReal *dmp) {
548   SNES_NASM *nasm = (SNES_NASM *)snes->data;
549 
550   PetscFunctionBegin;
551   *dmp = nasm->damping;
552   PetscFunctionReturn(0);
553 }
554 
555 /*
556   Input Parameters:
557 + snes - The solver
558 . B - The RHS vector
559 - X - The initial guess
560 
561   Output Parameters:
562 . Y - The solution update
563 
564   TODO: All scatters should be packed into one
565 */
566 PetscErrorCode SNESNASMSolveLocal_Private(SNES snes, Vec B, Vec Y, Vec X) {
567   SNES_NASM *nasm = (SNES_NASM *)snes->data;
568   SNES       subsnes;
569   PetscInt   i;
570   PetscReal  dmp;
571   Vec        Xl, Bl, Yl, Xlloc;
572   VecScatter iscat, oscat, gscat, oscat_copy;
573   DM         dm, subdm;
574   PCASMType  type;
575 
576   PetscFunctionBegin;
577   PetscCall(SNESNASMGetType(snes, &type));
578   PetscCall(SNESGetDM(snes, &dm));
579   PetscCall(VecSet(Y, 0));
580   if (nasm->eventrestrictinterp) PetscCall(PetscLogEventBegin(nasm->eventrestrictinterp, snes, 0, 0, 0));
581   for (i = 0; i < nasm->n; i++) {
582     /* scatter the solution to the global solution and the local solution */
583     Xl         = nasm->x[i];
584     Xlloc      = nasm->xl[i];
585     oscat      = nasm->oscatter[i];
586     oscat_copy = nasm->oscatter_copy[i];
587     gscat      = nasm->gscatter[i];
588     PetscCall(VecScatterBegin(oscat, X, Xl, INSERT_VALUES, SCATTER_FORWARD));
589     PetscCall(VecScatterBegin(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD));
590     if (B) {
591       /* scatter the RHS to the local RHS */
592       Bl = nasm->b[i];
593       PetscCall(VecScatterBegin(oscat_copy, B, Bl, INSERT_VALUES, SCATTER_FORWARD));
594     }
595   }
596   if (nasm->eventrestrictinterp) PetscCall(PetscLogEventEnd(nasm->eventrestrictinterp, snes, 0, 0, 0));
597 
598   if (nasm->eventsubsolve) PetscCall(PetscLogEventBegin(nasm->eventsubsolve, snes, 0, 0, 0));
599   for (i = 0; i < nasm->n; i++) {
600     Xl      = nasm->x[i];
601     Xlloc   = nasm->xl[i];
602     Yl      = nasm->y[i];
603     subsnes = nasm->subsnes[i];
604     PetscCall(SNESGetDM(subsnes, &subdm));
605     iscat      = nasm->iscatter[i];
606     oscat      = nasm->oscatter[i];
607     oscat_copy = nasm->oscatter_copy[i];
608     gscat      = nasm->gscatter[i];
609     PetscCall(VecScatterEnd(oscat, X, Xl, INSERT_VALUES, SCATTER_FORWARD));
610     PetscCall(VecScatterEnd(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD));
611     if (B) {
612       Bl = nasm->b[i];
613       PetscCall(VecScatterEnd(oscat_copy, B, Bl, INSERT_VALUES, SCATTER_FORWARD));
614     } else Bl = NULL;
615 
616     PetscCall(DMSubDomainRestrict(dm, oscat, gscat, subdm));
617     PetscCall(VecCopy(Xl, Yl));
618     PetscCall(SNESSolve(subsnes, Bl, Xl));
619     PetscCall(VecAYPX(Yl, -1.0, Xl));
620     PetscCall(VecScale(Yl, nasm->damping));
621     if (type == PC_ASM_BASIC) {
622       PetscCall(VecScatterBegin(oscat, Yl, Y, ADD_VALUES, SCATTER_REVERSE));
623       PetscCall(VecScatterEnd(oscat, Yl, Y, ADD_VALUES, SCATTER_REVERSE));
624     } else if (type == PC_ASM_RESTRICT) {
625       PetscCall(VecScatterBegin(iscat, Yl, Y, ADD_VALUES, SCATTER_REVERSE));
626       PetscCall(VecScatterEnd(iscat, Yl, Y, ADD_VALUES, SCATTER_REVERSE));
627     } else SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "Only basic and restrict types are supported for SNESNASM");
628   }
629   if (nasm->eventsubsolve) PetscCall(PetscLogEventEnd(nasm->eventsubsolve, snes, 0, 0, 0));
630   if (nasm->eventrestrictinterp) PetscCall(PetscLogEventBegin(nasm->eventrestrictinterp, snes, 0, 0, 0));
631   if (nasm->weight_set) PetscCall(VecPointwiseMult(Y, Y, nasm->weight));
632   if (nasm->eventrestrictinterp) PetscCall(PetscLogEventEnd(nasm->eventrestrictinterp, snes, 0, 0, 0));
633   PetscCall(SNESNASMGetDamping(snes, &dmp));
634   PetscCall(VecAXPY(X, dmp, Y));
635   PetscFunctionReturn(0);
636 }
637 
638 static PetscErrorCode SNESNASMComputeFinalJacobian_Private(SNES snes, Vec Xfinal) {
639   Vec        X    = Xfinal;
640   SNES_NASM *nasm = (SNES_NASM *)snes->data;
641   SNES       subsnes;
642   PetscInt   i, lag = 1;
643   Vec        Xlloc, Xl, Fl, F;
644   VecScatter oscat, gscat;
645   DM         dm, subdm;
646 
647   PetscFunctionBegin;
648   if (nasm->fjtype == 2) X = nasm->xinit;
649   F = snes->vec_func;
650   if (snes->normschedule == SNES_NORM_NONE) PetscCall(SNESComputeFunction(snes, X, F));
651   PetscCall(SNESComputeJacobian(snes, X, snes->jacobian, snes->jacobian_pre));
652   PetscCall(SNESGetDM(snes, &dm));
653   if (nasm->eventrestrictinterp) PetscCall(PetscLogEventBegin(nasm->eventrestrictinterp, snes, 0, 0, 0));
654   if (nasm->fjtype != 1) {
655     for (i = 0; i < nasm->n; i++) {
656       Xlloc = nasm->xl[i];
657       gscat = nasm->gscatter[i];
658       PetscCall(VecScatterBegin(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD));
659     }
660   }
661   if (nasm->eventrestrictinterp) PetscCall(PetscLogEventEnd(nasm->eventrestrictinterp, snes, 0, 0, 0));
662   for (i = 0; i < nasm->n; i++) {
663     Fl      = nasm->subsnes[i]->vec_func;
664     Xl      = nasm->x[i];
665     Xlloc   = nasm->xl[i];
666     subsnes = nasm->subsnes[i];
667     oscat   = nasm->oscatter[i];
668     gscat   = nasm->gscatter[i];
669     if (nasm->fjtype != 1) PetscCall(VecScatterEnd(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD));
670     PetscCall(SNESGetDM(subsnes, &subdm));
671     PetscCall(DMSubDomainRestrict(dm, oscat, gscat, subdm));
672     if (nasm->fjtype != 1) {
673       PetscCall(DMLocalToGlobalBegin(subdm, Xlloc, INSERT_VALUES, Xl));
674       PetscCall(DMLocalToGlobalEnd(subdm, Xlloc, INSERT_VALUES, Xl));
675     }
676     if (subsnes->lagjacobian == -1) subsnes->lagjacobian = -2;
677     else if (subsnes->lagjacobian > 1) lag = subsnes->lagjacobian;
678     PetscCall(SNESComputeFunction(subsnes, Xl, Fl));
679     PetscCall(SNESComputeJacobian(subsnes, Xl, subsnes->jacobian, subsnes->jacobian_pre));
680     if (lag > 1) subsnes->lagjacobian = lag;
681   }
682   PetscFunctionReturn(0);
683 }
684 
685 static PetscErrorCode SNESSolve_NASM(SNES snes) {
686   Vec              F;
687   Vec              X;
688   Vec              B;
689   Vec              Y;
690   PetscInt         i;
691   PetscReal        fnorm = 0.0;
692   SNESNormSchedule normschedule;
693   SNES_NASM       *nasm = (SNES_NASM *)snes->data;
694 
695   PetscFunctionBegin;
696 
697   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);
698 
699   PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite));
700   X = snes->vec_sol;
701   Y = snes->vec_sol_update;
702   F = snes->vec_func;
703   B = snes->vec_rhs;
704 
705   PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
706   snes->iter = 0;
707   snes->norm = 0.;
708   PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
709   snes->reason = SNES_CONVERGED_ITERATING;
710   PetscCall(SNESGetNormSchedule(snes, &normschedule));
711   if (normschedule == SNES_NORM_ALWAYS || normschedule == SNES_NORM_INITIAL_ONLY || normschedule == SNES_NORM_INITIAL_FINAL_ONLY) {
712     /* compute the initial function and preconditioned update delX */
713     if (!snes->vec_func_init_set) {
714       PetscCall(SNESComputeFunction(snes, X, F));
715     } else snes->vec_func_init_set = PETSC_FALSE;
716 
717     PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- ||F||  */
718     SNESCheckFunctionNorm(snes, fnorm);
719     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
720     snes->iter = 0;
721     snes->norm = fnorm;
722     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
723     PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0));
724     PetscCall(SNESMonitor(snes, 0, snes->norm));
725 
726     /* test convergence */
727     PetscUseTypeMethod(snes, converged, 0, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP);
728     if (snes->reason) PetscFunctionReturn(0);
729   } else {
730     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
731     PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0));
732     PetscCall(SNESMonitor(snes, 0, snes->norm));
733   }
734 
735   /* Call general purpose update function */
736   PetscTryTypeMethod(snes, update, snes->iter);
737   /* copy the initial solution over for later */
738   if (nasm->fjtype == 2) PetscCall(VecCopy(X, nasm->xinit));
739 
740   for (i = 0; i < snes->max_its; i++) {
741     PetscCall(SNESNASMSolveLocal_Private(snes, B, Y, X));
742     if (normschedule == SNES_NORM_ALWAYS || ((i == snes->max_its - 1) && (normschedule == SNES_NORM_INITIAL_FINAL_ONLY || normschedule == SNES_NORM_FINAL_ONLY))) {
743       PetscCall(SNESComputeFunction(snes, X, F));
744       PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- ||F||  */
745       SNESCheckFunctionNorm(snes, fnorm);
746     }
747     /* Monitor convergence */
748     PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
749     snes->iter = i + 1;
750     snes->norm = fnorm;
751     PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
752     PetscCall(SNESLogConvergenceHistory(snes, snes->norm, 0));
753     PetscCall(SNESMonitor(snes, snes->iter, snes->norm));
754     /* Test for convergence */
755     if (normschedule == SNES_NORM_ALWAYS) PetscUseTypeMethod(snes, converged, snes->iter, 0.0, 0.0, fnorm, &snes->reason, snes->cnvP);
756     if (snes->reason) break;
757     /* Call general purpose update function */
758     PetscTryTypeMethod(snes, update, snes->iter);
759   }
760   if (nasm->finaljacobian) {
761     PetscCall(SNESNASMComputeFinalJacobian_Private(snes, X));
762     SNESCheckJacobianDomainerror(snes);
763   }
764   if (normschedule == SNES_NORM_ALWAYS) {
765     if (i == snes->max_its) {
766       PetscCall(PetscInfo(snes, "Maximum number of iterations has been reached: %" PetscInt_FMT "\n", snes->max_its));
767       if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
768     }
769   } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; /* NASM is meant to be used as a preconditioner */
770   PetscFunctionReturn(0);
771 }
772 
773 /*MC
774   SNESNASM - Nonlinear Additive Schwarz
775 
776    Options Database:
777 +  -snes_nasm_log - enable logging events for the communication and solve stages
778 .  -snes_nasm_type <basic,restrict> - type of subdomain update used
779 .  -snes_asm_damping <dmp> - the new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains)
780 .  -snes_nasm_finaljacobian - compute the local and global jacobians of the final iterate
781 .  -snes_nasm_finaljacobian_type <finalinner,finalouter,initial> - pick state the jacobian is calculated at
782 .  -sub_snes_ - options prefix of the subdomain nonlinear solves
783 .  -sub_ksp_ - options prefix of the subdomain Krylov solver
784 -  -sub_pc_ - options prefix of the subdomain preconditioner
785 
786    Level: advanced
787 
788    Developer Note: This is a non-Newton based nonlinear solver that does not directly require a Jacobian; hence the flag snes->usesksp is set to
789        false and SNESView() and -snes_view do not display a KSP object. However, if the flag nasm->finaljacobian is set (for example, if
790        NASM is used as a nonlinear preconditioner for  KSPASPIN) then SNESSetUpMatrices() is called to generate the Jacobian (needed by KSPASPIN)
791        and this utilizes the KSP for storing the matrices, but the KSP is never used for solving a linear system. Note that when SNESNASM is
792        used by SNESASPIN they share the same Jacobian matrices because SNESSetUp() (called on the outer SNES KSPASPIN) causes the inner SNES
793        object (in this case SNESNASM) to inherit the outer Jacobian matrices.
794 
795    References:
796 .  * - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers",
797    SIAM Review, 57(4), 2015
798 
799 .seealso: `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType`, `SNESNASMSetType()`, `SNESNASMGetType()`, `SNESNASMSetSubdomains()`, `SNESNASMGetSubdomains()`, `SNESNASMGetSubdomainVecs()`, `SNESNASMSetComputeFinalJacobian()`, `SNESNASMSetDamping()`, `SNESNASMGetDamping()`
800 M*/
801 
802 PETSC_EXTERN PetscErrorCode SNESCreate_NASM(SNES snes) {
803   SNES_NASM *nasm;
804 
805   PetscFunctionBegin;
806   PetscCall(PetscNewLog(snes, &nasm));
807   snes->data = (void *)nasm;
808 
809   nasm->n             = PETSC_DECIDE;
810   nasm->subsnes       = NULL;
811   nasm->x             = NULL;
812   nasm->xl            = NULL;
813   nasm->y             = NULL;
814   nasm->b             = NULL;
815   nasm->oscatter      = NULL;
816   nasm->oscatter_copy = NULL;
817   nasm->iscatter      = NULL;
818   nasm->gscatter      = NULL;
819   nasm->damping       = 1.;
820 
821   nasm->type          = PC_ASM_BASIC;
822   nasm->finaljacobian = PETSC_FALSE;
823   nasm->weight_set    = PETSC_FALSE;
824 
825   snes->ops->destroy        = SNESDestroy_NASM;
826   snes->ops->setup          = SNESSetUp_NASM;
827   snes->ops->setfromoptions = SNESSetFromOptions_NASM;
828   snes->ops->view           = SNESView_NASM;
829   snes->ops->solve          = SNESSolve_NASM;
830   snes->ops->reset          = SNESReset_NASM;
831 
832   snes->usesksp = PETSC_FALSE;
833   snes->usesnpc = PETSC_FALSE;
834 
835   snes->alwayscomputesfinalresidual = PETSC_FALSE;
836 
837   nasm->fjtype              = 0;
838   nasm->xinit               = NULL;
839   nasm->eventrestrictinterp = 0;
840   nasm->eventsubsolve       = 0;
841 
842   if (!snes->tolerancesset) {
843     snes->max_its   = 10000;
844     snes->max_funcs = 10000;
845   }
846 
847   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetType_C", SNESNASMSetType_NASM));
848   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetType_C", SNESNASMGetType_NASM));
849   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetSubdomains_C", SNESNASMSetSubdomains_NASM));
850   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetSubdomains_C", SNESNASMGetSubdomains_NASM));
851   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetDamping_C", SNESNASMSetDamping_NASM));
852   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetDamping_C", SNESNASMGetDamping_NASM));
853   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMGetSubdomainVecs_C", SNESNASMGetSubdomainVecs_NASM));
854   PetscCall(PetscObjectComposeFunction((PetscObject)snes, "SNESNASMSetComputeFinalJacobian_C", SNESNASMSetComputeFinalJacobian_NASM));
855   PetscFunctionReturn(0);
856 }
857 
858 /*@
859    SNESNASMGetSNES - Gets a subsolver
860 
861    Not collective
862 
863    Input Parameters:
864 +  snes - the SNES context
865 -  i - the number of the subsnes to get
866 
867    Output Parameters:
868 .  subsnes - the subsolver context
869 
870    Level: intermediate
871 
872 .seealso: `SNESNASM`, `SNESNASMGetNumber()`
873 @*/
874 PetscErrorCode SNESNASMGetSNES(SNES snes, PetscInt i, SNES *subsnes) {
875   SNES_NASM *nasm = (SNES_NASM *)snes->data;
876 
877   PetscFunctionBegin;
878   PetscCheck(i >= 0 && i < nasm->n, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_OUTOFRANGE, "No such subsolver");
879   *subsnes = nasm->subsnes[i];
880   PetscFunctionReturn(0);
881 }
882 
883 /*@
884    SNESNASMGetNumber - Gets number of subsolvers
885 
886    Not collective
887 
888    Input Parameters:
889 .  snes - the SNES context
890 
891    Output Parameters:
892 .  n - the number of subsolvers
893 
894    Level: intermediate
895 
896 .seealso: `SNESNASM`, `SNESNASMGetSNES()`
897 @*/
898 PetscErrorCode SNESNASMGetNumber(SNES snes, PetscInt *n) {
899   SNES_NASM *nasm = (SNES_NASM *)snes->data;
900 
901   PetscFunctionBegin;
902   *n = nasm->n;
903   PetscFunctionReturn(0);
904 }
905 
906 /*@
907    SNESNASMSetWeight - Sets weight to use when adding overlapping updates
908 
909    Collective
910 
911    Input Parameters:
912 +  snes - the SNES context
913 -  weight - the weights to use (typically 1/N for each dof, where N is the number of patches it appears in)
914 
915    Level: intermediate
916 
917 .seealso: `SNESNASM`
918 @*/
919 PetscErrorCode SNESNASMSetWeight(SNES snes, Vec weight) {
920   SNES_NASM *nasm = (SNES_NASM *)snes->data;
921 
922   PetscFunctionBegin;
923 
924   PetscCall(VecDestroy(&nasm->weight));
925   nasm->weight_set = PETSC_TRUE;
926   nasm->weight     = weight;
927   PetscCall(PetscObjectReference((PetscObject)nasm->weight));
928 
929   PetscFunctionReturn(0);
930 }
931