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