Actual source code: nasm.c
petsc-3.9.4 2018-09-11
1: #include <petsc/private/snesimpl.h>
2: #include <petscdm.h>
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 */
23: /* logging events */
24: PetscLogEvent eventrestrictinterp;
25: PetscLogEvent eventsubsolve;
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;
31: const char *const SNESNASMTypes[] = {"NONE","RESTRICT","INTERPOLATE","BASIC","PCASMType","PC_ASM_",0};
32: const char *const SNESNASMFJTypes[] = {"FINALOUTER","FINALINNER","INITIAL"};
34: static PetscErrorCode SNESReset_NASM(SNES snes)
35: {
36: SNES_NASM *nasm = (SNES_NASM*)snes->data;
38: PetscInt i;
41: for (i=0; i<nasm->n; i++) {
42: if (nasm->xl) { VecDestroy(&nasm->xl[i]); }
43: if (nasm->x) { VecDestroy(&nasm->x[i]); }
44: if (nasm->y) { VecDestroy(&nasm->y[i]); }
45: if (nasm->b) { VecDestroy(&nasm->b[i]); }
47: if (nasm->subsnes) { SNESDestroy(&nasm->subsnes[i]); }
48: if (nasm->oscatter) { VecScatterDestroy(&nasm->oscatter[i]); }
49: if (nasm->oscatter_copy) { VecScatterDestroy(&nasm->oscatter_copy[i]); }
50: if (nasm->iscatter) { VecScatterDestroy(&nasm->iscatter[i]); }
51: if (nasm->gscatter) { VecScatterDestroy(&nasm->gscatter[i]); }
52: }
54: PetscFree(nasm->x);
55: PetscFree(nasm->xl);
56: PetscFree(nasm->y);
57: PetscFree(nasm->b);
59: if (nasm->xinit) {VecDestroy(&nasm->xinit);}
61: PetscFree(nasm->subsnes);
62: PetscFree(nasm->oscatter);
63: PetscFree(nasm->oscatter_copy);
64: PetscFree(nasm->iscatter);
65: PetscFree(nasm->gscatter);
67: if (nasm->weight_set) {
68: VecDestroy(&nasm->weight);
69: }
71: nasm->eventrestrictinterp = 0;
72: nasm->eventsubsolve = 0;
73: return(0);
74: }
76: static PetscErrorCode SNESDestroy_NASM(SNES snes)
77: {
81: SNESReset_NASM(snes);
82: PetscFree(snes->data);
83: return(0);
84: }
86: static PetscErrorCode DMGlobalToLocalSubDomainDirichletHook_Private(DM dm,Vec g,InsertMode mode,Vec l,void *ctx)
87: {
89: Vec bcs = (Vec)ctx;
92: VecCopy(bcs,l);
93: return(0);
94: }
96: static PetscErrorCode SNESSetUp_NASM(SNES snes)
97: {
98: SNES_NASM *nasm = (SNES_NASM*)snes->data;
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;
110: if (!nasm->subsnes) {
111: SNESGetDM(snes,&dm);
112: if (dm) {
113: nasm->usesdm = PETSC_TRUE;
114: DMCreateDomainDecomposition(dm,&nasm->n,NULL,NULL,NULL,&subdms);
115: if (!subdms) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"DM has no default decomposition defined. Set subsolves manually with SNESNASMSetSubdomains().");
116: DMCreateDomainDecompositionScatters(dm,nasm->n,subdms,&nasm->iscatter,&nasm->oscatter,&nasm->gscatter);
117: PetscMalloc1(nasm->n, &nasm->oscatter_copy);
118: for (i=0; i<nasm->n; i++) {
119: VecScatterCopy(nasm->oscatter[i], &nasm->oscatter_copy[i]);
120: }
122: SNESGetOptionsPrefix(snes, &optionsprefix);
123: PetscMalloc1(nasm->n,&nasm->subsnes);
124: for (i=0; i<nasm->n; i++) {
125: SNESCreate(PETSC_COMM_SELF,&nasm->subsnes[i]);
126: PetscObjectIncrementTabLevel((PetscObject)nasm->subsnes[i], (PetscObject)snes, 1);
127: SNESAppendOptionsPrefix(nasm->subsnes[i],optionsprefix);
128: SNESAppendOptionsPrefix(nasm->subsnes[i],"sub_");
129: SNESSetDM(nasm->subsnes[i],subdms[i]);
130: MPI_Comm_size(PetscObjectComm((PetscObject)nasm->subsnes[i]),&size);
131: if (size == 1) {
132: SNESGetKSP(nasm->subsnes[i],&ksp);
133: KSPGetPC(ksp,&pc);
134: KSPSetType(ksp,KSPPREONLY);
135: PCSetType(pc,PCLU);
136: }
137: SNESSetFromOptions(nasm->subsnes[i]);
138: DMDestroy(&subdms[i]);
139: }
140: PetscFree(subdms);
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: PetscCalloc1(nasm->n,&nasm->x);
146: }
147: if (!nasm->xl) {
148: PetscCalloc1(nasm->n,&nasm->xl);
149: }
150: if (!nasm->y) {
151: PetscCalloc1(nasm->n,&nasm->y);
152: }
153: if (!nasm->b) {
154: PetscCalloc1(nasm->n,&nasm->b);
155: }
157: for (i=0; i<nasm->n; i++) {
158: SNESGetFunction(nasm->subsnes[i],&F,NULL,NULL);
159: if (!nasm->x[i]) {VecDuplicate(F,&nasm->x[i]);}
160: if (!nasm->y[i]) {VecDuplicate(F,&nasm->y[i]);}
161: if (!nasm->b[i]) {VecDuplicate(F,&nasm->b[i]);}
162: if (!nasm->xl[i]) {
163: SNESGetDM(nasm->subsnes[i],&subdm);
164: DMCreateLocalVector(subdm,&nasm->xl[i]);
165: DMGlobalToLocalHookAdd(subdm,DMGlobalToLocalSubDomainDirichletHook_Private,NULL,nasm->xl[i]);
166: }
167: }
168: if (nasm->finaljacobian) {
169: SNESSetUpMatrices(snes);
170: if (nasm->fjtype == 2) {
171: VecDuplicate(snes->vec_sol,&nasm->xinit);
172: }
173: for (i=0; i<nasm->n;i++) {
174: SNESSetUpMatrices(nasm->subsnes[i]);
175: }
176: }
177: return(0);
178: }
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;
188: PetscOptionsHead(PetscOptionsObject,"Nonlinear Additive Schwartz options");
189: PetscOptionsEnum("-snes_nasm_type","Type of restriction/extension","",SNESNASMTypes,(PetscEnum)nasm->type,(PetscEnum*)&asmtype,&flg);
190: if (flg) {SNESNASMSetType(snes,asmtype);}
191: flg = PETSC_FALSE;
192: monflg = PETSC_TRUE;
193: 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);
194: if (flg) {SNESNASMSetDamping(snes,nasm->damping);}
195: subviewflg = PETSC_FALSE;
196: PetscOptionsBool("-snes_nasm_sub_view","Print detailed information for every processor when using -snes_view","",subviewflg,&subviewflg,&flg);
197: if (flg) {
198: nasm->same_local_solves = PETSC_FALSE;
199: if (!subviewflg) {
200: nasm->same_local_solves = PETSC_TRUE;
201: }
202: }
203: PetscOptionsBool("-snes_nasm_finaljacobian","Compute the global jacobian of the final iterate (for ASPIN)","",nasm->finaljacobian,&nasm->finaljacobian,NULL);
204: PetscOptionsEList("-snes_nasm_finaljacobian_type","The type of the final jacobian computed.","",SNESNASMFJTypes,3,SNESNASMFJTypes[0],&nasm->fjtype,NULL);
205: PetscOptionsBool("-snes_nasm_log","Log times for subSNES solves and restriction","",monflg,&monflg,&flg);
206: if (flg) {
207: PetscLogEventRegister("SNESNASMSubSolve",((PetscObject)snes)->classid,&nasm->eventsubsolve);
208: PetscLogEventRegister("SNESNASMRestrict",((PetscObject)snes)->classid,&nasm->eventrestrictinterp);
209: }
210: PetscOptionsTail();
211: return(0);
212: }
214: static PetscErrorCode SNESView_NASM(SNES snes, PetscViewer viewer)
215: {
216: SNES_NASM *nasm = (SNES_NASM*)snes->data;
218: PetscMPIInt rank,size;
219: PetscInt i,N,bsz;
220: PetscBool iascii,isstring;
221: PetscViewer sviewer;
222: MPI_Comm comm;
225: PetscObjectGetComm((PetscObject)snes,&comm);
226: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
227: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);
228: MPI_Comm_rank(comm,&rank);
229: MPI_Comm_size(comm,&size);
230: MPIU_Allreduce(&nasm->n,&N,1,MPIU_INT,MPI_SUM,comm);
231: if (iascii) {
232: PetscViewerASCIIPrintf(viewer, " total subdomain blocks = %D\n",N);
233: if (nasm->same_local_solves) {
234: if (nasm->subsnes) {
235: PetscViewerASCIIPrintf(viewer," Local solve is the same for all blocks:\n");
236: PetscViewerASCIIPushTab(viewer);
237: PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
238: if (!rank) {
239: PetscViewerASCIIPushTab(viewer);
240: SNESView(nasm->subsnes[0],sviewer);
241: PetscViewerASCIIPopTab(viewer);
242: }
243: PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
244: PetscViewerASCIIPopTab(viewer);
245: }
246: } else {
247: /* print the solver on each block */
248: PetscViewerASCIIPushSynchronized(viewer);
249: PetscViewerASCIISynchronizedPrintf(viewer," [%d] number of local blocks = %D\n",(int)rank,nasm->n);
250: PetscViewerFlush(viewer);
251: PetscViewerASCIIPopSynchronized(viewer);
252: PetscViewerASCIIPrintf(viewer," Local solve info for each block is in the following SNES objects:\n");
253: PetscViewerASCIIPushTab(viewer);
254: PetscViewerASCIIPrintf(viewer,"- - - - - - - - - - - - - - - - - -\n");
255: PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
256: for (i=0; i<nasm->n; i++) {
257: VecGetLocalSize(nasm->x[i],&bsz);
258: PetscViewerASCIIPrintf(sviewer,"[%d] local block number %D, size = %D\n",(int)rank,i,bsz);
259: SNESView(nasm->subsnes[i],sviewer);
260: PetscViewerASCIIPrintf(sviewer,"- - - - - - - - - - - - - - - - - -\n");
261: }
262: PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
263: PetscViewerFlush(viewer);
264: PetscViewerASCIIPopTab(viewer);
265: }
266: } else if (isstring) {
267: PetscViewerStringSPrintf(viewer," blocks=%D,type=%s",N,SNESNASMTypes[nasm->type]);
268: PetscViewerGetSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
269: if (nasm->subsnes && !rank) {SNESView(nasm->subsnes[0],sviewer);}
270: PetscViewerRestoreSubViewer(viewer,PETSC_COMM_SELF,&sviewer);
271: }
272: return(0);
273: }
275: /*@
276: SNESNASMSetType - Set the type of subdomain update used
278: Logically Collective on SNES
280: Input Parameters:
281: + SNES - the SNES context
282: - type - the type of update, PC_ASM_BASIC or PC_ASM_RESTRICT
284: Level: intermediate
286: .keywords: SNES, NASM
288: .seealso: SNESNASM, SNESNASMGetType(), PCASMSetType()
289: @*/
290: PetscErrorCode SNESNASMSetType(SNES snes,PCASMType type)
291: {
293: PetscErrorCode (*f)(SNES,PCASMType);
296: PetscObjectQueryFunction((PetscObject)snes,"SNESNASMSetType_C",&f);
297: if (f) {(f)(snes,type);}
298: return(0);
299: }
301: static PetscErrorCode SNESNASMSetType_NASM(SNES snes,PCASMType type)
302: {
303: SNES_NASM *nasm = (SNES_NASM*)snes->data;
306: if (type != PC_ASM_BASIC && type != PC_ASM_RESTRICT) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_OUTOFRANGE,"SNESNASM only supports basic and restrict types");
307: nasm->type = type;
308: return(0);
309: }
311: /*@
312: SNESNASMGetType - Get the type of subdomain update used
314: Logically Collective on SNES
316: Input Parameters:
317: . SNES - the SNES context
319: Output Parameters:
320: . type - the type of update
322: Level: intermediate
324: .keywords: SNES, NASM
326: .seealso: SNESNASM, SNESNASMSetType(), PCASMGetType()
327: @*/
328: PetscErrorCode SNESNASMGetType(SNES snes,PCASMType *type)
329: {
333: PetscUseMethod(snes,"SNESNASMGetType_C",(SNES,PCASMType*),(snes,type));
334: return(0);
335: }
337: static PetscErrorCode SNESNASMGetType_NASM(SNES snes,PCASMType *type)
338: {
339: SNES_NASM *nasm = (SNES_NASM*)snes->data;
342: *type = nasm->type;
343: return(0);
344: }
346: /*@
347: SNESNASMSetSubdomains - Manually Set the context required to restrict and solve subdomain problems.
349: Not Collective
351: Input Parameters:
352: + SNES - the SNES context
353: . n - the number of local subdomains
354: . subsnes - solvers defined on the local subdomains
355: . iscatter - scatters into the nonoverlapping portions of the local subdomains
356: . oscatter - scatters into the overlapping portions of the local subdomains
357: - gscatter - scatters into the (ghosted) local vector of the local subdomain
359: Level: intermediate
361: .keywords: SNES, NASM
363: .seealso: SNESNASM, SNESNASMGetSubdomains()
364: @*/
365: PetscErrorCode SNESNASMSetSubdomains(SNES snes,PetscInt n,SNES subsnes[],VecScatter iscatter[],VecScatter oscatter[],VecScatter gscatter[])
366: {
368: PetscErrorCode (*f)(SNES,PetscInt,SNES*,VecScatter*,VecScatter*,VecScatter*);
371: PetscObjectQueryFunction((PetscObject)snes,"SNESNASMSetSubdomains_C",&f);
372: if (f) {(f)(snes,n,subsnes,iscatter,oscatter,gscatter);}
373: return(0);
374: }
376: static PetscErrorCode SNESNASMSetSubdomains_NASM(SNES snes,PetscInt n,SNES subsnes[],VecScatter iscatter[],VecScatter oscatter[],VecScatter gscatter[])
377: {
378: PetscInt i;
380: SNES_NASM *nasm = (SNES_NASM*)snes->data;
383: if (snes->setupcalled) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"SNESNASMSetSubdomains() should be called before calling SNESSetUp().");
385: /* tear down the previously set things */
386: SNESReset(snes);
388: nasm->n = n;
389: if (oscatter) {
390: for (i=0; i<n; i++) {PetscObjectReference((PetscObject)oscatter[i]);}
391: }
392: if (iscatter) {
393: for (i=0; i<n; i++) {PetscObjectReference((PetscObject)iscatter[i]);}
394: }
395: if (gscatter) {
396: for (i=0; i<n; i++) {PetscObjectReference((PetscObject)gscatter[i]);}
397: }
398: if (oscatter) {
399: PetscMalloc1(n,&nasm->oscatter);
400: PetscMalloc1(n,&nasm->oscatter_copy);
401: for (i=0; i<n; i++) {
402: nasm->oscatter[i] = oscatter[i];
403: VecScatterCopy(oscatter[i], &nasm->oscatter_copy[i]);
404: }
405: }
406: if (iscatter) {
407: PetscMalloc1(n,&nasm->iscatter);
408: for (i=0; i<n; i++) {
409: nasm->iscatter[i] = iscatter[i];
410: }
411: }
412: if (gscatter) {
413: PetscMalloc1(n,&nasm->gscatter);
414: for (i=0; i<n; i++) {
415: nasm->gscatter[i] = gscatter[i];
416: }
417: }
419: if (subsnes) {
420: PetscMalloc1(n,&nasm->subsnes);
421: for (i=0; i<n; i++) {
422: nasm->subsnes[i] = subsnes[i];
423: }
424: nasm->same_local_solves = PETSC_FALSE;
425: }
426: return(0);
427: }
429: /*@
430: SNESNASMGetSubdomains - Get the local subdomain context.
432: Not Collective
434: Input Parameters:
435: . SNES - the SNES context
437: Output Parameters:
438: + n - the number of local subdomains
439: . subsnes - solvers defined on the local subdomains
440: . iscatter - scatters into the nonoverlapping portions of the local subdomains
441: . oscatter - scatters into the overlapping portions of the local subdomains
442: - gscatter - scatters into the (ghosted) local vector of the local subdomain
444: Level: intermediate
446: .keywords: SNES, NASM
448: .seealso: SNESNASM, SNESNASMSetSubdomains()
449: @*/
450: PetscErrorCode SNESNASMGetSubdomains(SNES snes,PetscInt *n,SNES *subsnes[],VecScatter *iscatter[],VecScatter *oscatter[],VecScatter *gscatter[])
451: {
453: PetscErrorCode (*f)(SNES,PetscInt*,SNES**,VecScatter**,VecScatter**,VecScatter**);
456: PetscObjectQueryFunction((PetscObject)snes,"SNESNASMGetSubdomains_C",&f);
457: if (f) {(f)(snes,n,subsnes,iscatter,oscatter,gscatter);}
458: return(0);
459: }
461: static PetscErrorCode SNESNASMGetSubdomains_NASM(SNES snes,PetscInt *n,SNES *subsnes[],VecScatter *iscatter[],VecScatter *oscatter[],VecScatter *gscatter[])
462: {
463: SNES_NASM *nasm = (SNES_NASM*)snes->data;
466: if (n) *n = nasm->n;
467: if (oscatter) *oscatter = nasm->oscatter;
468: if (iscatter) *iscatter = nasm->iscatter;
469: if (gscatter) *gscatter = nasm->gscatter;
470: if (subsnes) {
471: *subsnes = nasm->subsnes;
472: nasm->same_local_solves = PETSC_FALSE;
473: }
474: return(0);
475: }
477: /*@
478: SNESNASMGetSubdomainVecs - Get the processor-local subdomain vectors
480: Not Collective
482: Input Parameters:
483: . SNES - the SNES context
485: Output Parameters:
486: + n - the number of local subdomains
487: . x - The subdomain solution vector
488: . y - The subdomain step vector
489: . b - The subdomain RHS vector
490: - xl - The subdomain local vectors (ghosted)
492: Level: developer
494: .keywords: SNES, NASM
496: .seealso: SNESNASM, SNESNASMGetSubdomains()
497: @*/
498: PetscErrorCode SNESNASMGetSubdomainVecs(SNES snes,PetscInt *n,Vec **x,Vec **y,Vec **b, Vec **xl)
499: {
501: PetscErrorCode (*f)(SNES,PetscInt*,Vec**,Vec**,Vec**,Vec**);
504: PetscObjectQueryFunction((PetscObject)snes,"SNESNASMGetSubdomainVecs_C",&f);
505: if (f) {(f)(snes,n,x,y,b,xl);}
506: return(0);
507: }
509: static PetscErrorCode SNESNASMGetSubdomainVecs_NASM(SNES snes,PetscInt *n,Vec **x,Vec **y,Vec **b,Vec **xl)
510: {
511: SNES_NASM *nasm = (SNES_NASM*)snes->data;
514: if (n) *n = nasm->n;
515: if (x) *x = nasm->x;
516: if (y) *y = nasm->y;
517: if (b) *b = nasm->b;
518: if (xl) *xl = nasm->xl;
519: return(0);
520: }
522: /*@
523: SNESNASMSetComputeFinalJacobian - Schedules the computation of the global and subdomain jacobians upon convergence
525: Collective on SNES
527: Input Parameters:
528: + SNES - the SNES context
529: - flg - indication of whether to compute the jacobians or not
531: Level: developer
533: Notes: This is used almost exclusively in the implementation of ASPIN, where the converged subdomain and global jacobian
534: is needed at each linear iteration.
536: .keywords: SNES, NASM, ASPIN
538: .seealso: SNESNASM, SNESNASMGetSubdomains()
539: @*/
540: PetscErrorCode SNESNASMSetComputeFinalJacobian(SNES snes,PetscBool flg)
541: {
542: PetscErrorCode (*f)(SNES,PetscBool);
546: PetscObjectQueryFunction((PetscObject)snes,"SNESNASMSetComputeFinalJacobian_C",&f);
547: if (f) {(f)(snes,flg);}
548: return(0);
549: }
551: static PetscErrorCode SNESNASMSetComputeFinalJacobian_NASM(SNES snes,PetscBool flg)
552: {
553: SNES_NASM *nasm = (SNES_NASM*)snes->data;
556: nasm->finaljacobian = flg;
557: if (flg) snes->usesksp = PETSC_TRUE;
558: return(0);
559: }
561: /*@
562: SNESNASMSetDamping - Sets the update damping for NASM
564: Logically collective on SNES
566: Input Parameters:
567: + SNES - the SNES context
568: - dmp - damping
570: Level: intermediate
572: Notes: The new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains)
574: .keywords: SNES, NASM, damping
576: .seealso: SNESNASM, SNESNASMGetDamping()
577: @*/
578: PetscErrorCode SNESNASMSetDamping(SNES snes,PetscReal dmp)
579: {
580: PetscErrorCode (*f)(SNES,PetscReal);
584: PetscObjectQueryFunction((PetscObject)snes,"SNESNASMSetDamping_C",(void (**)(void))&f);
585: if (f) {(f)(snes,dmp);}
586: return(0);
587: }
589: static PetscErrorCode SNESNASMSetDamping_NASM(SNES snes,PetscReal dmp)
590: {
591: SNES_NASM *nasm = (SNES_NASM*)snes->data;
594: nasm->damping = dmp;
595: return(0);
596: }
598: /*@
599: SNESNASMGetDamping - Gets the update damping for NASM
601: Not Collective
603: Input Parameters:
604: + SNES - the SNES context
605: - dmp - damping
607: Level: intermediate
609: .keywords: SNES, NASM, damping
611: .seealso: SNESNASM, SNESNASMSetDamping()
612: @*/
613: PetscErrorCode SNESNASMGetDamping(SNES snes,PetscReal *dmp)
614: {
618: PetscUseMethod(snes,"SNESNASMGetDamping_C",(SNES,PetscReal*),(snes,dmp));
619: return(0);
620: }
622: static PetscErrorCode SNESNASMGetDamping_NASM(SNES snes,PetscReal *dmp)
623: {
624: SNES_NASM *nasm = (SNES_NASM*)snes->data;
627: *dmp = nasm->damping;
628: return(0);
629: }
632: /*
633: Input Parameters:
634: + snes - The solver
635: . B - The RHS vector
636: - X - The initial guess
638: Output Parameters:
639: . Y - The solution update
641: TODO: All scatters should be packed into one
642: */
643: PetscErrorCode SNESNASMSolveLocal_Private(SNES snes,Vec B,Vec Y,Vec X)
644: {
645: SNES_NASM *nasm = (SNES_NASM*)snes->data;
646: SNES subsnes;
647: PetscInt i;
648: PetscReal dmp;
650: Vec Xl,Bl,Yl,Xlloc;
651: VecScatter iscat,oscat,gscat,oscat_copy;
652: DM dm,subdm;
653: PCASMType type;
656: SNESNASMGetType(snes,&type);
657: SNESGetDM(snes,&dm);
658: VecSet(Y,0);
659: if (nasm->eventrestrictinterp) {PetscLogEventBegin(nasm->eventrestrictinterp,snes,0,0,0);}
660: for (i=0; i<nasm->n; i++) {
661: /* scatter the solution to the global solution and the local solution */
662: Xl = nasm->x[i];
663: Xlloc = nasm->xl[i];
664: oscat = nasm->oscatter[i];
665: oscat_copy = nasm->oscatter_copy[i];
666: gscat = nasm->gscatter[i];
667: VecScatterBegin(oscat,X,Xl,INSERT_VALUES,SCATTER_FORWARD);
668: VecScatterBegin(gscat,X,Xlloc,INSERT_VALUES,SCATTER_FORWARD);
669: if (B) {
670: /* scatter the RHS to the local RHS */
671: Bl = nasm->b[i];
672: VecScatterBegin(oscat_copy,B,Bl,INSERT_VALUES,SCATTER_FORWARD);
673: }
674: }
675: if (nasm->eventrestrictinterp) {PetscLogEventEnd(nasm->eventrestrictinterp,snes,0,0,0);}
678: if (nasm->eventsubsolve) {PetscLogEventBegin(nasm->eventsubsolve,snes,0,0,0);}
679: for (i=0; i<nasm->n; i++) {
680: Xl = nasm->x[i];
681: Xlloc = nasm->xl[i];
682: Yl = nasm->y[i];
683: subsnes = nasm->subsnes[i];
684: SNESGetDM(subsnes,&subdm);
685: iscat = nasm->iscatter[i];
686: oscat = nasm->oscatter[i];
687: oscat_copy = nasm->oscatter_copy[i];
688: gscat = nasm->gscatter[i];
689: VecScatterEnd(oscat,X,Xl,INSERT_VALUES,SCATTER_FORWARD);
690: VecScatterEnd(gscat,X,Xlloc,INSERT_VALUES,SCATTER_FORWARD);
691: if (B) {
692: Bl = nasm->b[i];
693: VecScatterEnd(oscat_copy,B,Bl,INSERT_VALUES,SCATTER_FORWARD);
694: } else Bl = NULL;
696: DMSubDomainRestrict(dm,oscat,gscat,subdm);
697: VecCopy(Xl,Yl);
698: SNESSolve(subsnes,Bl,Xl);
699: VecAYPX(Yl,-1.0,Xl);
700: VecScale(Yl, nasm->damping);
701: if (type == PC_ASM_BASIC) {
702: VecScatterBegin(oscat,Yl,Y,ADD_VALUES,SCATTER_REVERSE);
703: } else if (type == PC_ASM_RESTRICT) {
704: VecScatterBegin(iscat,Yl,Y,ADD_VALUES,SCATTER_REVERSE);
705: } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Only basic and restrict types are supported for SNESNASM");
706: }
707: if (nasm->eventsubsolve) {PetscLogEventEnd(nasm->eventsubsolve,snes,0,0,0);}
708: if (nasm->eventrestrictinterp) {PetscLogEventBegin(nasm->eventrestrictinterp,snes,0,0,0);}
709: for (i=0; i<nasm->n; i++) {
710: Yl = nasm->y[i];
711: iscat = nasm->iscatter[i];
712: oscat = nasm->oscatter[i];
713: if (type == PC_ASM_BASIC) {
714: VecScatterEnd(oscat,Yl,Y,ADD_VALUES,SCATTER_REVERSE);
715: } else if (type == PC_ASM_RESTRICT) {
716: VecScatterEnd(iscat,Yl,Y,ADD_VALUES,SCATTER_REVERSE);
717: } else SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE,"Only basic and restrict types are supported for SNESNASM");
718: }
719: if (nasm->weight_set) {
720: VecPointwiseMult(Y,Y,nasm->weight);
721: }
722: if (nasm->eventrestrictinterp) {PetscLogEventEnd(nasm->eventrestrictinterp,snes,0,0,0);}
723: SNESNASMGetDamping(snes,&dmp);
724: VecAXPY(X,dmp,Y);
725: return(0);
726: }
728: static PetscErrorCode SNESNASMComputeFinalJacobian_Private(SNES snes, Vec Xfinal)
729: {
730: Vec X = Xfinal;
731: SNES_NASM *nasm = (SNES_NASM*)snes->data;
732: SNES subsnes;
733: PetscInt i,lag = 1;
735: Vec Xlloc,Xl,Fl,F;
736: VecScatter oscat,gscat;
737: DM dm,subdm;
740: if (nasm->fjtype == 2) X = nasm->xinit;
741: F = snes->vec_func;
742: if (snes->normschedule == SNES_NORM_NONE) {SNESComputeFunction(snes,X,F);}
743: SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);
744: SNESGetDM(snes,&dm);
745: if (nasm->eventrestrictinterp) {PetscLogEventBegin(nasm->eventrestrictinterp,snes,0,0,0);}
746: if (nasm->fjtype != 1) {
747: for (i=0; i<nasm->n; i++) {
748: Xlloc = nasm->xl[i];
749: gscat = nasm->gscatter[i];
750: VecScatterBegin(gscat,X,Xlloc,INSERT_VALUES,SCATTER_FORWARD);
751: }
752: }
753: if (nasm->eventrestrictinterp) {PetscLogEventEnd(nasm->eventrestrictinterp,snes,0,0,0);}
754: for (i=0; i<nasm->n; i++) {
755: Fl = nasm->subsnes[i]->vec_func;
756: Xl = nasm->x[i];
757: Xlloc = nasm->xl[i];
758: subsnes = nasm->subsnes[i];
759: oscat = nasm->oscatter[i];
760: gscat = nasm->gscatter[i];
761: if (nasm->fjtype != 1) {VecScatterEnd(gscat,X,Xlloc,INSERT_VALUES,SCATTER_FORWARD);}
762: SNESGetDM(subsnes,&subdm);
763: DMSubDomainRestrict(dm,oscat,gscat,subdm);
764: if (nasm->fjtype != 1) {
765: DMLocalToGlobalBegin(subdm,Xlloc,INSERT_VALUES,Xl);
766: DMLocalToGlobalEnd(subdm,Xlloc,INSERT_VALUES,Xl);
767: }
768: if (subsnes->lagjacobian == -1) subsnes->lagjacobian = -2;
769: else if (subsnes->lagjacobian > 1) lag = subsnes->lagjacobian;
770: SNESComputeFunction(subsnes,Xl,Fl);
771: SNESComputeJacobian(subsnes,Xl,subsnes->jacobian,subsnes->jacobian_pre);
772: if (lag > 1) subsnes->lagjacobian = lag;
773: }
774: return(0);
775: }
777: static PetscErrorCode SNESSolve_NASM(SNES snes)
778: {
779: Vec F;
780: Vec X;
781: Vec B;
782: Vec Y;
783: PetscInt i;
784: PetscReal fnorm = 0.0;
785: PetscErrorCode ierr;
786: SNESNormSchedule normschedule;
787: SNES_NASM *nasm = (SNES_NASM*)snes->data;
791: 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);
793: PetscCitationsRegister(SNESCitation,&SNEScite);
794: X = snes->vec_sol;
795: Y = snes->vec_sol_update;
796: F = snes->vec_func;
797: B = snes->vec_rhs;
799: PetscObjectSAWsTakeAccess((PetscObject)snes);
800: snes->iter = 0;
801: snes->norm = 0.;
802: PetscObjectSAWsGrantAccess((PetscObject)snes);
803: snes->reason = SNES_CONVERGED_ITERATING;
804: SNESGetNormSchedule(snes, &normschedule);
805: if (normschedule == SNES_NORM_ALWAYS || normschedule == SNES_NORM_INITIAL_ONLY || normschedule == SNES_NORM_INITIAL_FINAL_ONLY) {
806: /* compute the initial function and preconditioned update delX */
807: if (!snes->vec_func_init_set) {
808: SNESComputeFunction(snes,X,F);
809: } else snes->vec_func_init_set = PETSC_FALSE;
811: VecNorm(F, NORM_2, &fnorm); /* fnorm <- ||F|| */
812: SNESCheckFunctionNorm(snes,fnorm);
813: PetscObjectSAWsTakeAccess((PetscObject)snes);
814: snes->iter = 0;
815: snes->norm = fnorm;
816: PetscObjectSAWsGrantAccess((PetscObject)snes);
817: SNESLogConvergenceHistory(snes,snes->norm,0);
818: SNESMonitor(snes,0,snes->norm);
820: /* test convergence */
821: (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);
822: if (snes->reason) return(0);
823: } else {
824: PetscObjectSAWsGrantAccess((PetscObject)snes);
825: SNESLogConvergenceHistory(snes,snes->norm,0);
826: SNESMonitor(snes,0,snes->norm);
827: }
829: /* Call general purpose update function */
830: if (snes->ops->update) {
831: (*snes->ops->update)(snes, snes->iter);
832: }
833: /* copy the initial solution over for later */
834: if (nasm->fjtype == 2) {VecCopy(X,nasm->xinit);}
836: for (i=0; i < snes->max_its; i++) {
837: SNESNASMSolveLocal_Private(snes,B,Y,X);
838: if (normschedule == SNES_NORM_ALWAYS || ((i == snes->max_its - 1) && (normschedule == SNES_NORM_INITIAL_FINAL_ONLY || normschedule == SNES_NORM_FINAL_ONLY))) {
839: SNESComputeFunction(snes,X,F);
840: VecNorm(F, NORM_2, &fnorm); /* fnorm <- ||F|| */
841: SNESCheckFunctionNorm(snes,fnorm);
842: }
843: /* Monitor convergence */
844: PetscObjectSAWsTakeAccess((PetscObject)snes);
845: snes->iter = i+1;
846: snes->norm = fnorm;
847: PetscObjectSAWsGrantAccess((PetscObject)snes);
848: SNESLogConvergenceHistory(snes,snes->norm,0);
849: SNESMonitor(snes,snes->iter,snes->norm);
850: /* Test for convergence */
851: if (normschedule == SNES_NORM_ALWAYS) {(*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);}
852: if (snes->reason) break;
853: /* Call general purpose update function */
854: if (snes->ops->update) {(*snes->ops->update)(snes, snes->iter);}
855: }
856: if (nasm->finaljacobian) {SNESNASMComputeFinalJacobian_Private(snes,X);}
857: if (normschedule == SNES_NORM_ALWAYS) {
858: if (i == snes->max_its) {
859: PetscInfo1(snes,"Maximum number of iterations has been reached: %D\n",snes->max_its);
860: if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
861: }
862: } else if (!snes->reason) snes->reason = SNES_CONVERGED_ITS; /* NASM is meant to be used as a preconditioner */
863: return(0);
864: }
866: /*MC
867: SNESNASM - Nonlinear Additive Schwartz
869: Options Database:
870: + -snes_nasm_log - enable logging events for the communication and solve stages
871: . -snes_nasm_type <basic,restrict> - type of subdomain update used
872: . -snes_asm_damping <dmp> - the new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains)
873: . -snes_nasm_finaljacobian - compute the local and global jacobians of the final iterate
874: . -snes_nasm_finaljacobian_type <finalinner,finalouter,initial> - pick state the jacobian is calculated at
875: . -sub_snes_ - options prefix of the subdomain nonlinear solves
876: . -sub_ksp_ - options prefix of the subdomain Krylov solver
877: - -sub_pc_ - options prefix of the subdomain preconditioner
879: Level: advanced
881: References:
882: . 1. - Peter R. Brune, Matthew G. Knepley, Barry F. Smith, and Xuemin Tu, "Composing Scalable Nonlinear Algebraic Solvers",
883: SIAM Review, 57(4), 2015
885: .seealso: SNESCreate(), SNES, SNESSetType(), SNESType (for list of available types), SNESNASMSetType(), SNESNASMGetType(), SNESNASMSetSubdomains(), SNESNASMGetSubdomains(), SNESNASMGetSubdomainVecs(), SNESNASMSetComputeFinalJacobian(), SNESNASMSetDamping(), SNESNASMGetDamping()
886: M*/
888: PETSC_EXTERN PetscErrorCode SNESCreate_NASM(SNES snes)
889: {
890: SNES_NASM *nasm;
894: PetscNewLog(snes,&nasm);
895: snes->data = (void*)nasm;
897: nasm->n = PETSC_DECIDE;
898: nasm->subsnes = 0;
899: nasm->x = 0;
900: nasm->xl = 0;
901: nasm->y = 0;
902: nasm->b = 0;
903: nasm->oscatter = 0;
904: nasm->oscatter_copy = 0;
905: nasm->iscatter = 0;
906: nasm->gscatter = 0;
907: nasm->damping = 1.;
909: nasm->type = PC_ASM_BASIC;
910: nasm->finaljacobian = PETSC_FALSE;
911: nasm->same_local_solves = PETSC_TRUE;
912: nasm->weight_set = PETSC_FALSE;
914: snes->ops->destroy = SNESDestroy_NASM;
915: snes->ops->setup = SNESSetUp_NASM;
916: snes->ops->setfromoptions = SNESSetFromOptions_NASM;
917: snes->ops->view = SNESView_NASM;
918: snes->ops->solve = SNESSolve_NASM;
919: snes->ops->reset = SNESReset_NASM;
921: snes->usesksp = PETSC_FALSE;
922: snes->usesnpc = PETSC_FALSE;
924: snes->alwayscomputesfinalresidual = PETSC_FALSE;
926: nasm->fjtype = 0;
927: nasm->xinit = NULL;
928: nasm->eventrestrictinterp = 0;
929: nasm->eventsubsolve = 0;
931: if (!snes->tolerancesset) {
932: snes->max_its = 10000;
933: snes->max_funcs = 10000;
934: }
936: PetscObjectComposeFunction((PetscObject)snes,"SNESNASMSetType_C",SNESNASMSetType_NASM);
937: PetscObjectComposeFunction((PetscObject)snes,"SNESNASMGetType_C",SNESNASMGetType_NASM);
938: PetscObjectComposeFunction((PetscObject)snes,"SNESNASMSetSubdomains_C",SNESNASMSetSubdomains_NASM);
939: PetscObjectComposeFunction((PetscObject)snes,"SNESNASMGetSubdomains_C",SNESNASMGetSubdomains_NASM);
940: PetscObjectComposeFunction((PetscObject)snes,"SNESNASMSetDamping_C",SNESNASMSetDamping_NASM);
941: PetscObjectComposeFunction((PetscObject)snes,"SNESNASMGetDamping_C",SNESNASMGetDamping_NASM);
942: PetscObjectComposeFunction((PetscObject)snes,"SNESNASMGetSubdomainVecs_C",SNESNASMGetSubdomainVecs_NASM);
943: PetscObjectComposeFunction((PetscObject)snes,"SNESNASMSetComputeFinalJacobian_C",SNESNASMSetComputeFinalJacobian_NASM);
944: return(0);
945: }
947: /*@
948: SNESNASMGetSNES - Gets a subsolver
950: Not collective
952: Input Parameters:
953: + snes - the SNES context
954: - i - the number of the subsnes to get
956: Output Parameters:
957: . subsnes - the subsolver context
959: Level: intermediate
961: .keywords: SNES, NASM
963: .seealso: SNESNASM, SNESNASMGetNumber()
964: @*/
965: PetscErrorCode SNESNASMGetSNES(SNES snes,PetscInt i,SNES *subsnes)
966: {
967: SNES_NASM *nasm = (SNES_NASM*)snes->data;
970: if (i < 0 || i >= nasm->n) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_OUTOFRANGE,"No such subsolver");
971: *subsnes = nasm->subsnes[i];
972: return(0);
973: }
975: /*@
976: SNESNASMGetNumber - Gets number of subsolvers
978: Not collective
980: Input Parameters:
981: . snes - the SNES context
983: Output Parameters:
984: . n - the number of subsolvers
986: Level: intermediate
988: .keywords: SNES, NASM
990: .seealso: SNESNASM, SNESNASMGetSNES()
991: @*/
992: PetscErrorCode SNESNASMGetNumber(SNES snes,PetscInt *n)
993: {
994: SNES_NASM *nasm = (SNES_NASM*)snes->data;
997: *n = nasm->n;
998: return(0);
999: }
1001: /*@
1002: SNESNASMSetWeight - Sets weight to use when adding overlapping updates
1004: Collective
1006: Input Parameters:
1007: + snes - the SNES context
1008: - weight - the weights to use (typically 1/N for each dof, where N is the number of patches it appears in)
1010: Level: intermediate
1012: .keywords: SNES, NASM
1014: .seealso: SNESNASM
1015: @*/
1016: PetscErrorCode SNESNASMSetWeight(SNES snes,Vec weight)
1017: {
1018: SNES_NASM *nasm = (SNES_NASM*)snes->data;
1023: VecDestroy(&nasm->weight);
1024: nasm->weight_set = PETSC_TRUE;
1025: nasm->weight = weight;
1026: PetscObjectReference((PetscObject)nasm->weight);
1028: return(0);
1029: }