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
SNESReset_NASM(SNES snes)33 static PetscErrorCode SNESReset_NASM(SNES snes)
34 {
35 SNES_NASM *nasm = (SNES_NASM *)snes->data;
36 PetscInt i;
37
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]));
44
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 }
51
52 PetscCall(PetscFree(nasm->x));
53 PetscCall(PetscFree(nasm->xl));
54 PetscCall(PetscFree(nasm->y));
55 PetscCall(PetscFree(nasm->b));
56
57 if (nasm->xinit) PetscCall(VecDestroy(&nasm->xinit));
58
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));
64
65 if (nasm->weight_set) PetscCall(VecDestroy(&nasm->weight));
66
67 nasm->eventrestrictinterp = 0;
68 nasm->eventsubsolve = 0;
69 PetscFunctionReturn(PETSC_SUCCESS);
70 }
71
SNESDestroy_NASM(SNES snes)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 }
87
DMGlobalToLocalSubDomainDirichletHook_Private(DM dm,Vec g,InsertMode mode,Vec l,PetscCtx ctx)88 static PetscErrorCode DMGlobalToLocalSubDomainDirichletHook_Private(DM dm, Vec g, InsertMode mode, Vec l, PetscCtx ctx)
89 {
90 Vec bcs = (Vec)ctx;
91
92 PetscFunctionBegin;
93 PetscCall(VecCopy(bcs, l));
94 PetscFunctionReturn(PETSC_SUCCESS);
95 }
96
SNESSetUp_NASM(SNES snes)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;
105
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]));
116
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->ctxcompute) {
126 PetscCall(SNESSetComputeApplicationContext(nasm->subsnes[i], snes->ops->ctxcompute, snes->ops->ctxdestroy));
127 } else {
128 PetscCtx ctx;
129
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));
144
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 }
163
SNESSetFromOptions_NASM(SNES snes,PetscOptionItems PetscOptionsObject)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;
169
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 }
189
SNESView_NASM(SNES snes,PetscViewer viewer)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 isascii, isstring;
196 PetscViewer sviewer;
197 MPI_Comm comm;
198 PetscViewerFormat format;
199 const char *prefix;
200
201 PetscFunctionBegin;
202 PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
203 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
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 (isascii) {
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 }
253
254 /*@
255 SNESNASMSetType - Set the type of subdomain update used for the nonlinear additive Schwarz solver `SNESNASM`
256
257 Logically Collective
258
259 Input Parameters:
260 + snes - the `SNES` context
261 - type - the type of update, `PC_ASM_BASIC` or `PC_ASM_RESTRICT`
262
263 Options Database Key:
264 . -snes_nasm_type <basic,restrict> - type of subdomain update used
265
266 Level: intermediate
267
268 .seealso: [](ch_snes), `SNES`, `SNESNASM`, `SNESNASMGetType()`, `PCASMSetType()`, `PC_ASM_BASIC`, `PC_ASM_RESTRICT`, `PCASMType`
269 @*/
SNESNASMSetType(SNES snes,PCASMType type)270 PetscErrorCode SNESNASMSetType(SNES snes, PCASMType type)
271 {
272 PetscFunctionBegin;
273 PetscTryMethod(snes, "SNESNASMSetType_C", (SNES, PCASMType), (snes, type));
274 PetscFunctionReturn(PETSC_SUCCESS);
275 }
276
SNESNASMSetType_NASM(SNES snes,PCASMType type)277 static PetscErrorCode SNESNASMSetType_NASM(SNES snes, PCASMType type)
278 {
279 SNES_NASM *nasm = (SNES_NASM *)snes->data;
280
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 }
286
287 /*@
288 SNESNASMGetType - Get the type of subdomain update used for the nonlinear additive Schwarz solver `SNESNASM`
289
290 Logically Collective
291
292 Input Parameter:
293 . snes - the `SNES` context
294
295 Output Parameter:
296 . type - the type of update
297
298 Level: intermediate
299
300 .seealso: [](ch_snes), `SNES`, `SNESNASM`, `SNESNASMSetType()`, `PCASMGetType()`, `PC_ASM_BASIC`, `PC_ASM_RESTRICT`, `PCASMType`
301 @*/
SNESNASMGetType(SNES snes,PCASMType * type)302 PetscErrorCode SNESNASMGetType(SNES snes, PCASMType *type)
303 {
304 PetscFunctionBegin;
305 PetscUseMethod(snes, "SNESNASMGetType_C", (SNES, PCASMType *), (snes, type));
306 PetscFunctionReturn(PETSC_SUCCESS);
307 }
308
SNESNASMGetType_NASM(SNES snes,PCASMType * type)309 static PetscErrorCode SNESNASMGetType_NASM(SNES snes, PCASMType *type)
310 {
311 SNES_NASM *nasm = (SNES_NASM *)snes->data;
312
313 PetscFunctionBegin;
314 *type = nasm->type;
315 PetscFunctionReturn(PETSC_SUCCESS);
316 }
317
318 /*@
319 SNESNASMSetSubdomains - Manually Set the context required to restrict and solve subdomain problems in the nonlinear additive Schwarz solver
320
321 Logically Collective
322
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
330
331 Level: intermediate
332
333 .seealso: [](ch_snes), `SNES`, `SNESNASM`, `SNESNASMGetSubdomains()`
334 @*/
SNESNASMSetSubdomains(SNES snes,PetscInt n,SNES subsnes[],VecScatter iscatter[],VecScatter oscatter[],VecScatter gscatter[])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 *);
338
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 }
344
SNESNASMSetSubdomains_NASM(SNES snes,PetscInt n,SNES subsnes[],VecScatter iscatter[],VecScatter oscatter[],VecScatter gscatter[])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;
349
350 PetscFunctionBegin;
351 PetscCheck(!snes->setupcalled, PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_WRONGSTATE, "SNESNASMSetSubdomains() should be called before calling SNESSetUp().");
352
353 /* tear down the previously set things */
354 PetscCall(SNESReset(snes));
355
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 }
382
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 }
389
390 /*@
391 SNESNASMGetSubdomains - Get the local subdomain contexts for the nonlinear additive Schwarz solver
392
393 Not Collective but some of the objects returned will be parallel
394
395 Input Parameter:
396 . snes - the `SNES` context
397
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
404
405 Level: intermediate
406
407 .seealso: [](ch_snes), `SNES`, `SNESNASM`, `SNESNASMSetSubdomains()`
408 @*/
SNESNASMGetSubdomains(SNES snes,PetscInt * n,SNES * subsnes[],VecScatter * iscatter[],VecScatter * oscatter[],VecScatter * gscatter[])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 **);
412
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 }
418
SNESNASMGetSubdomains_NASM(SNES snes,PetscInt * n,SNES * subsnes[],VecScatter * iscatter[],VecScatter * oscatter[],VecScatter * gscatter[])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;
422
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 }
431
432 /*@
433 SNESNASMGetSubdomainVecs - Get the processor-local subdomain vectors for the nonlinear additive Schwarz solver
434
435 Not Collective
436
437 Input Parameter:
438 . snes - the `SNES` context
439
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)
446
447 Level: developer
448
449 .seealso: [](ch_snes), `SNES`, `SNESNASM`, `SNESNASMGetSubdomains()`
450 @*/
SNESNASMGetSubdomainVecs(SNES snes,PetscInt * n,Vec * x[],Vec * y[],Vec * b[],Vec * xl[])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 **);
454
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 }
460
SNESNASMGetSubdomainVecs_NASM(SNES snes,PetscInt * n,Vec ** x,Vec ** y,Vec ** b,Vec ** xl)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;
464
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 }
473
474 /*@
475 SNESNASMSetComputeFinalJacobian - Schedules the computation of the global and subdomain Jacobians upon convergence for the
476 nonlinear additive Schwarz solver
477
478 Collective
479
480 Input Parameters:
481 + snes - the SNES context
482 - flg - `PETSC_TRUE` to compute the Jacobians
483
484 Level: developer
485
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.
489
490 .seealso: [](ch_snes), `SNES`, `SNESNASM`, `SNESNASMGetSubdomains()`
491 @*/
SNESNASMSetComputeFinalJacobian(SNES snes,PetscBool flg)492 PetscErrorCode SNESNASMSetComputeFinalJacobian(SNES snes, PetscBool flg)
493 {
494 PetscErrorCode (*f)(SNES, PetscBool);
495
496 PetscFunctionBegin;
497 PetscCall(PetscObjectQueryFunction((PetscObject)snes, "SNESNASMSetComputeFinalJacobian_C", &f));
498 if (f) PetscCall((f)(snes, flg));
499 PetscFunctionReturn(PETSC_SUCCESS);
500 }
501
SNESNASMSetComputeFinalJacobian_NASM(SNES snes,PetscBool flg)502 static PetscErrorCode SNESNASMSetComputeFinalJacobian_NASM(SNES snes, PetscBool flg)
503 {
504 SNES_NASM *nasm = (SNES_NASM *)snes->data;
505
506 PetscFunctionBegin;
507 nasm->finaljacobian = flg;
508 PetscFunctionReturn(PETSC_SUCCESS);
509 }
510
511 /*@
512 SNESNASMSetDamping - Sets the update damping for `SNESNASM` the nonlinear additive Schwarz solver
513
514 Logically Collective
515
516 Input Parameters:
517 + snes - the `SNES` context
518 - dmp - damping
519
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)
522
523 Level: intermediate
524
525 Note:
526 The new solution is obtained as old solution plus dmp times (sum of the solutions on the subdomains)
527
528 .seealso: [](ch_snes), `SNES`, `SNESNASM`, `SNESNASMGetDamping()`
529 @*/
SNESNASMSetDamping(SNES snes,PetscReal dmp)530 PetscErrorCode SNESNASMSetDamping(SNES snes, PetscReal dmp)
531 {
532 PetscFunctionBegin;
533 PetscTryMethod(snes, "SNESNASMSetDamping_C", (SNES, PetscReal), (snes, dmp));
534 PetscFunctionReturn(PETSC_SUCCESS);
535 }
536
SNESNASMSetDamping_NASM(SNES snes,PetscReal dmp)537 static PetscErrorCode SNESNASMSetDamping_NASM(SNES snes, PetscReal dmp)
538 {
539 SNES_NASM *nasm = (SNES_NASM *)snes->data;
540
541 PetscFunctionBegin;
542 nasm->damping = dmp;
543 PetscFunctionReturn(PETSC_SUCCESS);
544 }
545
546 /*@
547 SNESNASMGetDamping - Gets the update damping for `SNESNASM` the nonlinear additive Schwarz solver
548
549 Not Collective
550
551 Input Parameter:
552 . snes - the `SNES` context
553
554 Output Parameter:
555 . dmp - damping
556
557 Level: intermediate
558
559 .seealso: [](ch_snes), `SNES`, `SNESNASM`, `SNESNASMSetDamping()`
560 @*/
SNESNASMGetDamping(SNES snes,PetscReal * dmp)561 PetscErrorCode SNESNASMGetDamping(SNES snes, PetscReal *dmp)
562 {
563 PetscFunctionBegin;
564 PetscUseMethod(snes, "SNESNASMGetDamping_C", (SNES, PetscReal *), (snes, dmp));
565 PetscFunctionReturn(PETSC_SUCCESS);
566 }
567
SNESNASMGetDamping_NASM(SNES snes,PetscReal * dmp)568 static PetscErrorCode SNESNASMGetDamping_NASM(SNES snes, PetscReal *dmp)
569 {
570 SNES_NASM *nasm = (SNES_NASM *)snes->data;
571
572 PetscFunctionBegin;
573 *dmp = nasm->damping;
574 PetscFunctionReturn(PETSC_SUCCESS);
575 }
576
577 /*
578 Input Parameters:
579 + snes - The solver
580 . B - The RHS vector
581 - X - The initial guess
582
583 Output Parameter:
584 . Y - The solution update
585
586 TODO: All scatters should be packed into one
587 */
SNESNASMSolveLocal_Private(SNES snes,Vec B,Vec Y,Vec X)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;
598
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));
612
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));
620
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;
625
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;
641
642 PetscCall(SNESGetDM(subsnes, &subdm));
643 PetscCall(DMSNESGetBoundaryLocal(subdm, &bl, &bctx));
644 if (bl) PetscCall((*bl)(subdm, Xlloc, bctx));
645
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 }
667
SNESNASMComputeFinalJacobian_Private(SNES snes,Vec Xfinal)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;
677
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 SNESCheckJacobianDomainError(snes);
684 PetscCall(SNESGetDM(snes, &dm));
685 if (nasm->eventrestrictinterp) PetscCall(PetscLogEventBegin(nasm->eventrestrictinterp, snes, 0, 0, 0));
686 if (nasm->fjtype != 1) {
687 for (i = 0; i < nasm->n; i++) {
688 Xlloc = nasm->xl[i];
689 gscat = nasm->gscatter[i];
690 PetscCall(VecScatterBegin(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD));
691 }
692 }
693 if (nasm->eventrestrictinterp) PetscCall(PetscLogEventEnd(nasm->eventrestrictinterp, snes, 0, 0, 0));
694 for (i = 0; i < nasm->n; i++) {
695 Fl = nasm->subsnes[i]->vec_func;
696 Xl = nasm->x[i];
697 Xlloc = nasm->xl[i];
698 subsnes = nasm->subsnes[i];
699 oscat = nasm->oscatter[i];
700 gscat = nasm->gscatter[i];
701 if (nasm->fjtype != 1) PetscCall(VecScatterEnd(gscat, X, Xlloc, INSERT_VALUES, SCATTER_FORWARD));
702 PetscCall(SNESGetDM(subsnes, &subdm));
703 PetscCall(DMSubDomainRestrict(dm, oscat, gscat, subdm));
704 if (nasm->fjtype != 1) {
705 PetscCall(DMLocalToGlobalBegin(subdm, Xlloc, INSERT_VALUES, Xl));
706 PetscCall(DMLocalToGlobalEnd(subdm, Xlloc, INSERT_VALUES, Xl));
707 }
708 if (subsnes->lagjacobian == -1) subsnes->lagjacobian = -2;
709 else if (subsnes->lagjacobian > 1) lag = subsnes->lagjacobian;
710 PetscCall(SNESComputeFunction(subsnes, Xl, Fl));
711 PetscCall(SNESComputeJacobian(subsnes, Xl, subsnes->jacobian, subsnes->jacobian_pre));
712 if (lag > 1) subsnes->lagjacobian = lag;
713 }
714 PetscFunctionReturn(PETSC_SUCCESS);
715 }
716
SNESSolve_NASM(SNES snes)717 static PetscErrorCode SNESSolve_NASM(SNES snes)
718 {
719 Vec F;
720 Vec X;
721 Vec B;
722 Vec Y;
723 PetscInt i;
724 PetscReal fnorm = 0.0;
725 SNESNormSchedule normschedule;
726 SNES_NASM *nasm = (SNES_NASM *)snes->data;
727
728 PetscFunctionBegin;
729 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
731 PetscCall(PetscCitationsRegister(SNESCitation, &SNEScite));
732 X = snes->vec_sol;
733 Y = snes->vec_sol_update;
734 F = snes->vec_func;
735 B = snes->vec_rhs;
736
737 PetscCall(PetscObjectSAWsTakeAccess((PetscObject)snes));
738 snes->iter = 0;
739 snes->norm = 0.;
740 PetscCall(PetscObjectSAWsGrantAccess((PetscObject)snes));
741 snes->reason = SNES_CONVERGED_ITERATING;
742 PetscCall(SNESGetNormSchedule(snes, &normschedule));
743 if (normschedule == SNES_NORM_ALWAYS || normschedule == SNES_NORM_INITIAL_ONLY || normschedule == SNES_NORM_INITIAL_FINAL_ONLY || !snes->max_its) {
744 /* compute the initial function and preconditioned update delX */
745 if (!snes->vec_func_init_set) PetscCall(SNESComputeFunction(snes, X, F));
746 else snes->vec_func_init_set = PETSC_FALSE;
747
748 PetscCall(VecNorm(F, NORM_2, &fnorm)); /* fnorm <- ||F|| */
749 SNESCheckFunctionDomainError(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));
755
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 }
765
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));
770
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 SNESCheckFunctionDomainError(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 }
797
798 /*MC
799 SNESNASM - Nonlinear Additive Schwarz solver {cite}`ck02`, {cite}`bruneknepleysmithtu15`
800
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
810
811 Level: advanced
812
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
816
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.
825
826 .seealso: [](ch_snes), `SNESCreate()`, `SNES`, `SNESSetType()`, `SNESType`, `SNESNASMSetType()`, `SNESNASMGetType()`, `SNESNASMSetSubdomains()`, `SNESNASMGetSubdomains()`,
827 `SNESNASMGetSubdomainVecs()`, `SNESNASMSetComputeFinalJacobian()`, `SNESNASMSetDamping()`, `SNESNASMGetDamping()`, `SNESNASMSetWeight()`,
828 `SNESNASMGetSNES()`, `SNESNASMGetNumber()`
829 M*/
830
SNESCreate_NASM(SNES snes)831 PETSC_EXTERN PetscErrorCode SNESCreate_NASM(SNES snes)
832 {
833 SNES_NASM *nasm;
834
835 PetscFunctionBegin;
836 PetscCall(PetscNew(&nasm));
837 snes->data = (void *)nasm;
838
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.;
850
851 nasm->type = PC_ASM_BASIC;
852 nasm->finaljacobian = PETSC_FALSE;
853 nasm->weight_set = PETSC_FALSE;
854
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;
861
862 snes->usesksp = PETSC_FALSE;
863 snes->usesnpc = PETSC_FALSE;
864
865 snes->alwayscomputesfinalresidual = PETSC_FALSE;
866
867 nasm->fjtype = 0;
868 nasm->xinit = NULL;
869 nasm->eventrestrictinterp = 0;
870 nasm->eventsubsolve = 0;
871
872 PetscCall(SNESParametersInitialize(snes));
873 PetscObjectParameterSetDefault(snes, max_funcs, 10000);
874 PetscObjectParameterSetDefault(snes, max_its, 10000);
875
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 }
886
887 /*@
888 SNESNASMGetSNES - Gets a subsolver
889
890 Not Collective
891
892 Input Parameters:
893 + snes - the `SNES` context
894 - i - the number of the subsnes to get
895
896 Output Parameter:
897 . subsnes - the subsolver context
898
899 Level: intermediate
900
901 .seealso: [](ch_snes), `SNESNASM`, `SNESNASMGetNumber()`
902 @*/
SNESNASMGetSNES(SNES snes,PetscInt i,SNES * subsnes)903 PetscErrorCode SNESNASMGetSNES(SNES snes, PetscInt i, SNES *subsnes)
904 {
905 SNES_NASM *nasm = (SNES_NASM *)snes->data;
906
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 }
912
913 /*@
914 SNESNASMGetNumber - Gets number of subsolvers
915
916 Not Collective
917
918 Input Parameter:
919 . snes - the `SNES` context
920
921 Output Parameter:
922 . n - the number of subsolvers
923
924 Level: intermediate
925
926 .seealso: [](ch_snes), `SNESNASM`, `SNESNASMGetSNES()`
927 @*/
SNESNASMGetNumber(SNES snes,PetscInt * n)928 PetscErrorCode SNESNASMGetNumber(SNES snes, PetscInt *n)
929 {
930 SNES_NASM *nasm = (SNES_NASM *)snes->data;
931
932 PetscFunctionBegin;
933 *n = nasm->n;
934 PetscFunctionReturn(PETSC_SUCCESS);
935 }
936
937 /*@
938 SNESNASMSetWeight - Sets weight to use when adding overlapping updates
939
940 Collective
941
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)
945
946 Level: intermediate
947
948 .seealso: [](ch_snes), `SNESNASM`
949 @*/
SNESNASMSetWeight(SNES snes,Vec weight)950 PetscErrorCode SNESNASMSetWeight(SNES snes, Vec weight)
951 {
952 SNES_NASM *nasm = (SNES_NASM *)snes->data;
953
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 }
961