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