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