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