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