Actual source code: dmdasnes.c
1: #include <petscdmda.h>
2: #include <petsc/private/dmimpl.h>
3: #include <petsc/private/snesimpl.h>
5: /* This structure holds the user-provided DMDA callbacks */
6: typedef struct {
7: PetscErrorCode (*residuallocal)(DMDALocalInfo *, void *, void *, void *);
8: PetscErrorCode (*jacobianlocal)(DMDALocalInfo *, void *, Mat, Mat, void *);
9: PetscErrorCode (*objectivelocal)(DMDALocalInfo *, void *, PetscReal *, void *);
11: PetscErrorCode (*residuallocalvec)(DMDALocalInfo *, Vec, Vec, void *);
12: PetscErrorCode (*jacobianlocalvec)(DMDALocalInfo *, Vec, Mat, Mat, void *);
13: PetscErrorCode (*objectivelocalvec)(DMDALocalInfo *, Vec, PetscReal *, void *);
14: void *residuallocalctx;
15: void *jacobianlocalctx;
16: void *objectivelocalctx;
17: InsertMode residuallocalimode;
19: /* For Picard iteration defined locally */
20: PetscErrorCode (*rhsplocal)(DMDALocalInfo *, void *, void *, void *);
21: PetscErrorCode (*jacobianplocal)(DMDALocalInfo *, void *, Mat, Mat, void *);
22: void *picardlocalctx;
23: } DMSNES_DA;
25: static PetscErrorCode DMSNESDestroy_DMDA(DMSNES sdm)
26: {
27: PetscFunctionBegin;
28: PetscCall(PetscFree(sdm->data));
29: PetscFunctionReturn(PETSC_SUCCESS);
30: }
32: static PetscErrorCode DMSNESDuplicate_DMDA(DMSNES oldsdm, DMSNES sdm)
33: {
34: PetscFunctionBegin;
35: PetscCall(PetscNew((DMSNES_DA **)&sdm->data));
36: if (oldsdm->data) PetscCall(PetscMemcpy(sdm->data, oldsdm->data, sizeof(DMSNES_DA)));
37: PetscFunctionReturn(PETSC_SUCCESS);
38: }
40: static PetscErrorCode DMDASNESGetContext(DM dm, DMSNES sdm, DMSNES_DA **dmdasnes)
41: {
42: PetscFunctionBegin;
43: *dmdasnes = NULL;
44: if (!sdm->data) {
45: PetscCall(PetscNew((DMSNES_DA **)&sdm->data));
46: sdm->ops->destroy = DMSNESDestroy_DMDA;
47: sdm->ops->duplicate = DMSNESDuplicate_DMDA;
48: }
49: *dmdasnes = (DMSNES_DA *)sdm->data;
50: PetscFunctionReturn(PETSC_SUCCESS);
51: }
53: static PetscErrorCode SNESComputeFunction_DMDA(SNES snes, Vec X, Vec F, void *ctx)
54: {
55: DM dm;
56: DMSNES_DA *dmdasnes = (DMSNES_DA *)ctx;
57: DMDALocalInfo info;
58: Vec Xloc;
59: void *x, *f;
61: PetscFunctionBegin;
65: PetscCheck(dmdasnes->residuallocal || dmdasnes->residuallocalvec, PetscObjectComm((PetscObject)snes), PETSC_ERR_PLIB, "Corrupt context");
66: PetscCall(SNESGetDM(snes, &dm));
67: PetscCall(DMGetLocalVector(dm, &Xloc));
68: PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
69: PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
70: PetscCall(DMDAGetLocalInfo(dm, &info));
71: switch (dmdasnes->residuallocalimode) {
72: case INSERT_VALUES: {
73: PetscCall(PetscLogEventBegin(SNES_FunctionEval, snes, X, F, 0));
74: if (dmdasnes->residuallocalvec) PetscCallBack("SNES DMDA local callback function", (*dmdasnes->residuallocalvec)(&info, Xloc, F, dmdasnes->residuallocalctx));
75: else {
76: PetscCall(DMDAVecGetArray(dm, Xloc, &x));
77: PetscCall(DMDAVecGetArray(dm, F, &f));
78: PetscCallBack("SNES DMDA local callback function", (*dmdasnes->residuallocal)(&info, x, f, dmdasnes->residuallocalctx));
79: PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
80: PetscCall(DMDAVecRestoreArray(dm, F, &f));
81: }
82: PetscCall(PetscLogEventEnd(SNES_FunctionEval, snes, X, F, 0));
83: } break;
84: case ADD_VALUES: {
85: Vec Floc;
86: PetscCall(DMGetLocalVector(dm, &Floc));
87: PetscCall(VecZeroEntries(Floc));
88: PetscCall(PetscLogEventBegin(SNES_FunctionEval, snes, X, F, 0));
89: if (dmdasnes->residuallocalvec) PetscCallBack("SNES DMDA local callback function", (*dmdasnes->residuallocalvec)(&info, Xloc, Floc, dmdasnes->residuallocalctx));
90: else {
91: PetscCall(DMDAVecGetArray(dm, Xloc, &x));
92: PetscCall(DMDAVecGetArray(dm, Floc, &f));
93: PetscCallBack("SNES DMDA local callback function", (*dmdasnes->residuallocal)(&info, x, f, dmdasnes->residuallocalctx));
94: PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
95: PetscCall(DMDAVecRestoreArray(dm, Floc, &f));
96: }
97: PetscCall(PetscLogEventEnd(SNES_FunctionEval, snes, X, F, 0));
98: PetscCall(VecZeroEntries(F));
99: PetscCall(DMLocalToGlobalBegin(dm, Floc, ADD_VALUES, F));
100: PetscCall(DMLocalToGlobalEnd(dm, Floc, ADD_VALUES, F));
101: PetscCall(DMRestoreLocalVector(dm, &Floc));
102: } break;
103: default:
104: SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_INCOMP, "Cannot use imode=%d", (int)dmdasnes->residuallocalimode);
105: }
106: PetscCall(DMRestoreLocalVector(dm, &Xloc));
107: if (snes->domainerror) PetscCall(VecSetInf(F));
108: PetscFunctionReturn(PETSC_SUCCESS);
109: }
111: static PetscErrorCode SNESComputeObjective_DMDA(SNES snes, Vec X, PetscReal *ob, void *ctx)
112: {
113: DM dm;
114: DMSNES_DA *dmdasnes = (DMSNES_DA *)ctx;
115: DMDALocalInfo info;
116: Vec Xloc;
117: void *x;
119: PetscFunctionBegin;
122: PetscAssertPointer(ob, 3);
123: PetscCheck(dmdasnes->objectivelocal || dmdasnes->objectivelocalvec, PetscObjectComm((PetscObject)snes), PETSC_ERR_PLIB, "Corrupt context");
124: PetscCall(SNESGetDM(snes, &dm));
125: PetscCall(DMGetLocalVector(dm, &Xloc));
126: PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
127: PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
128: PetscCall(DMDAGetLocalInfo(dm, &info));
129: if (dmdasnes->objectivelocalvec) PetscCallBack("SNES DMDA local callback objective", (*dmdasnes->objectivelocalvec)(&info, Xloc, ob, dmdasnes->objectivelocalctx));
130: else {
131: PetscCall(DMDAVecGetArray(dm, Xloc, &x));
132: PetscCallBack("SNES DMDA local callback objective", (*dmdasnes->objectivelocal)(&info, x, ob, dmdasnes->objectivelocalctx));
133: PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
134: }
135: PetscCall(DMRestoreLocalVector(dm, &Xloc));
136: PetscFunctionReturn(PETSC_SUCCESS);
137: }
139: /* Routine is called by example, hence must be labeled PETSC_EXTERN */
140: PETSC_EXTERN PetscErrorCode SNESComputeJacobian_DMDA(SNES snes, Vec X, Mat A, Mat B, void *ctx)
141: {
142: DM dm;
143: DMSNES_DA *dmdasnes = (DMSNES_DA *)ctx;
144: DMDALocalInfo info;
145: Vec Xloc;
146: void *x;
148: PetscFunctionBegin;
149: PetscCheck(dmdasnes->residuallocal || dmdasnes->residuallocalvec, PetscObjectComm((PetscObject)snes), PETSC_ERR_PLIB, "Corrupt context");
150: PetscCall(SNESGetDM(snes, &dm));
152: if (dmdasnes->jacobianlocal || dmdasnes->jacobianlocalctx) {
153: PetscCall(DMGetLocalVector(dm, &Xloc));
154: PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
155: PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
156: PetscCall(DMDAGetLocalInfo(dm, &info));
157: if (dmdasnes->jacobianlocalvec) PetscCallBack("SNES DMDA local callback Jacobian", (*dmdasnes->jacobianlocalvec)(&info, Xloc, A, B, dmdasnes->jacobianlocalctx));
158: else {
159: PetscCall(DMDAVecGetArray(dm, Xloc, &x));
160: PetscCallBack("SNES DMDA local callback Jacobian", (*dmdasnes->jacobianlocal)(&info, x, A, B, dmdasnes->jacobianlocalctx));
161: PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
162: }
163: PetscCall(DMRestoreLocalVector(dm, &Xloc));
164: } else {
165: MatFDColoring fdcoloring;
166: PetscCall(PetscObjectQuery((PetscObject)dm, "DMDASNES_FDCOLORING", (PetscObject *)&fdcoloring));
167: if (!fdcoloring) {
168: ISColoring coloring;
170: PetscCall(DMCreateColoring(dm, dm->coloringtype, &coloring));
171: PetscCall(MatFDColoringCreate(B, coloring, &fdcoloring));
172: switch (dm->coloringtype) {
173: case IS_COLORING_GLOBAL:
174: PetscCall(MatFDColoringSetFunction(fdcoloring, (PetscErrorCode(*)(void))SNESComputeFunction_DMDA, dmdasnes));
175: break;
176: default:
177: SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_SUP, "No support for coloring type '%s'", ISColoringTypes[dm->coloringtype]);
178: }
179: PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fdcoloring, ((PetscObject)dm)->prefix));
180: PetscCall(MatFDColoringSetFromOptions(fdcoloring));
181: PetscCall(MatFDColoringSetUp(B, coloring, fdcoloring));
182: PetscCall(ISColoringDestroy(&coloring));
183: PetscCall(PetscObjectCompose((PetscObject)dm, "DMDASNES_FDCOLORING", (PetscObject)fdcoloring));
184: PetscCall(PetscObjectDereference((PetscObject)fdcoloring));
186: /* The following breaks an ugly reference counting loop that deserves a paragraph. MatFDColoringApply() will call
187: * VecDuplicate() with the state Vec and store inside the MatFDColoring. This Vec will duplicate the Vec, but the
188: * MatFDColoring is composed with the DM. We dereference the DM here so that the reference count will eventually
189: * drop to 0. Note the code in DMDestroy() that exits early for a negative reference count. That code path will be
190: * taken when the PetscObjectList for the Vec inside MatFDColoring is destroyed.
191: */
192: PetscCall(PetscObjectDereference((PetscObject)dm));
193: }
194: PetscCall(MatFDColoringApply(B, fdcoloring, X, snes));
195: }
196: /* This will be redundant if the user called both, but it's too common to forget. */
197: if (A != B) {
198: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
199: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
200: }
201: PetscFunctionReturn(PETSC_SUCCESS);
202: }
204: /*@C
205: DMDASNESSetFunctionLocal - set a local residual evaluation function for use with `DMDA`
207: Logically Collective
209: Input Parameters:
210: + dm - `DM` to associate callback with
211: . imode - `INSERT_VALUES` if local function computes owned part, `ADD_VALUES` if it contributes to ghosted part
212: . func - local residual evaluation
213: - ctx - optional context for local residual evaluation
215: Calling sequence of `func`:
216: + info - `DMDALocalInfo` defining the subdomain to evaluate the residual on
217: . x - dimensional pointer to state at which to evaluate residual (e.g. PetscScalar *x or **x or ***x)
218: . f - dimensional pointer to residual, write the residual here (e.g. PetscScalar *f or **f or ***f)
219: - ctx - optional context passed above
221: Level: beginner
223: .seealso: [](ch_snes), `DMDA`, `DMDASNESSetJacobianLocal()`, `DMSNESSetFunction()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`
224: @*/
225: PetscErrorCode DMDASNESSetFunctionLocal(DM dm, InsertMode imode, PetscErrorCode (*func)(DMDALocalInfo *info, void *x, void *f, void *ctx), void *ctx)
226: {
227: DMSNES sdm;
228: DMSNES_DA *dmdasnes;
230: PetscFunctionBegin;
232: PetscCall(DMGetDMSNESWrite(dm, &sdm));
233: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
235: dmdasnes->residuallocalimode = imode;
236: dmdasnes->residuallocal = func;
237: dmdasnes->residuallocalctx = ctx;
239: PetscCall(DMSNESSetFunction(dm, SNESComputeFunction_DMDA, dmdasnes));
240: if (!sdm->ops->computejacobian) { /* Call us for the Jacobian too, can be overridden by the user. */
241: PetscCall(DMSNESSetJacobian(dm, SNESComputeJacobian_DMDA, dmdasnes));
242: }
243: PetscFunctionReturn(PETSC_SUCCESS);
244: }
246: /*@C
247: DMDASNESSetFunctionLocalVec - set a local residual evaluation function that operates on a local vector for `DMDA`
249: Logically Collective
251: Input Parameters:
252: + dm - `DM` to associate callback with
253: . imode - `INSERT_VALUES` if local function computes owned part, `ADD_VALUES` if it contributes to ghosted part
254: . func - local residual evaluation
255: - ctx - optional context for local residual evaluation
257: Calling sequence of `func`:
258: + info - `DMDALocalInfo` defining the subdomain to evaluate the residual on
259: . x - state vector at which to evaluate residual
260: . f - residual vector
261: - ctx - optional context passed above
263: Level: beginner
265: .seealso: [](ch_snes), `DMDA`, `DMDASNESSetFunctionLocal()`, `DMDASNESSetJacobianLocalVec()`, `DMSNESSetFunction()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`
266: @*/
267: PetscErrorCode DMDASNESSetFunctionLocalVec(DM dm, InsertMode imode, PetscErrorCode (*func)(DMDALocalInfo *info, Vec x, Vec f, void *ctx), void *ctx)
268: {
269: DMSNES sdm;
270: DMSNES_DA *dmdasnes;
272: PetscFunctionBegin;
274: PetscCall(DMGetDMSNESWrite(dm, &sdm));
275: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
277: dmdasnes->residuallocalimode = imode;
278: dmdasnes->residuallocalvec = func;
279: dmdasnes->residuallocalctx = ctx;
281: PetscCall(DMSNESSetFunction(dm, SNESComputeFunction_DMDA, dmdasnes));
282: if (!sdm->ops->computejacobian) { /* Call us for the Jacobian too, can be overridden by the user. */
283: PetscCall(DMSNESSetJacobian(dm, SNESComputeJacobian_DMDA, dmdasnes));
284: }
285: PetscFunctionReturn(PETSC_SUCCESS);
286: }
288: /*@C
289: DMDASNESSetJacobianLocal - set a local Jacobian evaluation function for use with `DMDA`
291: Logically Collective
293: Input Parameters:
294: + dm - `DM` to associate callback with
295: . func - local Jacobian evaluation
296: - ctx - optional context for local Jacobian evaluation
298: Calling sequence of `func`:
299: + info - `DMDALocalInfo` defining the subdomain to evaluate the Jacobian at
300: . x - dimensional pointer to state at which to evaluate Jacobian (e.g. PetscScalar *x or **x or ***x)
301: . J - Mat object for the Jacobian
302: . M - Mat object for the Jacobian preconditioner matrix, often `J`
303: - ctx - optional context passed above
305: Level: beginner
307: .seealso: [](ch_snes), `DMDA`, `DMDASNESSetFunctionLocal()`, `DMSNESSetJacobian()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`
308: @*/
309: PetscErrorCode DMDASNESSetJacobianLocal(DM dm, PetscErrorCode (*func)(DMDALocalInfo *info, void *x, Mat J, Mat M, void *ctx), void *ctx)
310: {
311: DMSNES sdm;
312: DMSNES_DA *dmdasnes;
314: PetscFunctionBegin;
316: PetscCall(DMGetDMSNESWrite(dm, &sdm));
317: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
319: dmdasnes->jacobianlocal = func;
320: dmdasnes->jacobianlocalctx = ctx;
322: PetscCall(DMSNESSetJacobian(dm, SNESComputeJacobian_DMDA, dmdasnes));
323: PetscFunctionReturn(PETSC_SUCCESS);
324: }
326: /*@C
327: DMDASNESSetJacobianLocalVec - set a local Jacobian evaluation function that operates on a local vector with `DMDA`
329: Logically Collective
331: Input Parameters:
332: + dm - `DM` to associate callback with
333: . func - local Jacobian evaluation
334: - ctx - optional context for local Jacobian evaluation
336: Calling sequence of `func`:
337: + info - `DMDALocalInfo` defining the subdomain to evaluate the Jacobian at
338: . x - state vector at which to evaluate Jacobian
339: . J - the Jacobian
340: . M - approximate Jacobian from which the preconditioner will be computed, often `J`
341: - ctx - optional context passed above
343: Level: beginner
345: .seealso: [](ch_snes), `DMDA`, `DMDASNESSetJacobianLocal()`, `DMDASNESSetFunctionLocalVec()`, `DMSNESSetJacobian()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`
346: @*/
347: PetscErrorCode DMDASNESSetJacobianLocalVec(DM dm, PetscErrorCode (*func)(DMDALocalInfo *info, Vec x, Mat J, Mat M, void *), void *ctx)
348: {
349: DMSNES sdm;
350: DMSNES_DA *dmdasnes;
352: PetscFunctionBegin;
354: PetscCall(DMGetDMSNESWrite(dm, &sdm));
355: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
357: dmdasnes->jacobianlocalvec = func;
358: dmdasnes->jacobianlocalctx = ctx;
360: PetscCall(DMSNESSetJacobian(dm, SNESComputeJacobian_DMDA, dmdasnes));
361: PetscFunctionReturn(PETSC_SUCCESS);
362: }
364: // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation
365: /*@C
366: DMDASNESSetObjectiveLocal - set a local residual evaluation function to used with a `DMDA`
368: Logically Collective
370: Input Parameters:
371: + dm - `DM` to associate callback with
372: . func - local objective evaluation, see `DMDASNESSetObjectiveLocal` for the calling sequence
373: - ctx - optional context for local residual evaluation
375: Level: beginner
377: .seealso: [](ch_snes), `DMDA`, `DMSNESSetFunction()`, `DMDASNESSetJacobianLocal()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMDASNESObjective`
378: @*/
379: PetscErrorCode DMDASNESSetObjectiveLocal(DM dm, DMDASNESObjective func, void *ctx)
380: {
381: DMSNES sdm;
382: DMSNES_DA *dmdasnes;
384: PetscFunctionBegin;
386: PetscCall(DMGetDMSNESWrite(dm, &sdm));
387: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
389: dmdasnes->objectivelocal = func;
390: dmdasnes->objectivelocalctx = ctx;
392: PetscCall(DMSNESSetObjective(dm, SNESComputeObjective_DMDA, dmdasnes));
393: PetscFunctionReturn(PETSC_SUCCESS);
394: }
396: // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation
397: /*@C
398: DMDASNESSetObjectiveLocalVec - set a local residual evaluation function that operates on a local vector with `DMDA`
400: Logically Collective
402: Input Parameters:
403: + dm - `DM` to associate callback with
404: . func - local objective evaluation, see `DMDASNESSetObjectiveLocalVec` for the calling sequence
405: - ctx - optional context for local residual evaluation
407: Level: beginner
409: .seealso: [](ch_snes), `DMDA`, `DMDASNESSetObjectiveLocal()`, `DMSNESSetFunction()`, `DMDASNESSetJacobianLocalVec()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMDASNESObjectiveVec`
410: @*/
411: PetscErrorCode DMDASNESSetObjectiveLocalVec(DM dm, DMDASNESObjectiveVec func, void *ctx)
412: {
413: DMSNES sdm;
414: DMSNES_DA *dmdasnes;
416: PetscFunctionBegin;
418: PetscCall(DMGetDMSNESWrite(dm, &sdm));
419: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
421: dmdasnes->objectivelocalvec = func;
422: dmdasnes->objectivelocalctx = ctx;
424: PetscCall(DMSNESSetObjective(dm, SNESComputeObjective_DMDA, dmdasnes));
425: PetscFunctionReturn(PETSC_SUCCESS);
426: }
428: static PetscErrorCode SNESComputePicard_DMDA(SNES snes, Vec X, Vec F, void *ctx)
429: {
430: DM dm;
431: DMSNES_DA *dmdasnes = (DMSNES_DA *)ctx;
432: DMDALocalInfo info;
433: Vec Xloc;
434: void *x, *f;
436: PetscFunctionBegin;
440: PetscCheck(dmdasnes->rhsplocal, PetscObjectComm((PetscObject)snes), PETSC_ERR_PLIB, "Corrupt context");
441: PetscCall(SNESGetDM(snes, &dm));
442: PetscCall(DMGetLocalVector(dm, &Xloc));
443: PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
444: PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
445: PetscCall(DMDAGetLocalInfo(dm, &info));
446: PetscCall(DMDAVecGetArray(dm, Xloc, &x));
447: switch (dmdasnes->residuallocalimode) {
448: case INSERT_VALUES: {
449: PetscCall(DMDAVecGetArray(dm, F, &f));
450: PetscCallBack("SNES Picard DMDA local callback function", (*dmdasnes->rhsplocal)(&info, x, f, dmdasnes->picardlocalctx));
451: PetscCall(DMDAVecRestoreArray(dm, F, &f));
452: } break;
453: case ADD_VALUES: {
454: Vec Floc;
455: PetscCall(DMGetLocalVector(dm, &Floc));
456: PetscCall(VecZeroEntries(Floc));
457: PetscCall(DMDAVecGetArray(dm, Floc, &f));
458: PetscCallBack("SNES Picard DMDA local callback function", (*dmdasnes->rhsplocal)(&info, x, f, dmdasnes->picardlocalctx));
459: PetscCall(DMDAVecRestoreArray(dm, Floc, &f));
460: PetscCall(VecZeroEntries(F));
461: PetscCall(DMLocalToGlobalBegin(dm, Floc, ADD_VALUES, F));
462: PetscCall(DMLocalToGlobalEnd(dm, Floc, ADD_VALUES, F));
463: PetscCall(DMRestoreLocalVector(dm, &Floc));
464: } break;
465: default:
466: SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_INCOMP, "Cannot use imode=%d", (int)dmdasnes->residuallocalimode);
467: }
468: PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
469: PetscCall(DMRestoreLocalVector(dm, &Xloc));
470: PetscFunctionReturn(PETSC_SUCCESS);
471: }
473: static PetscErrorCode SNESComputePicardJacobian_DMDA(SNES snes, Vec X, Mat A, Mat B, void *ctx)
474: {
475: DM dm;
476: DMSNES_DA *dmdasnes = (DMSNES_DA *)ctx;
477: DMDALocalInfo info;
478: Vec Xloc;
479: void *x;
481: PetscFunctionBegin;
482: PetscCheck(dmdasnes->jacobianplocal, PetscObjectComm((PetscObject)snes), PETSC_ERR_PLIB, "Corrupt context");
483: PetscCall(SNESGetDM(snes, &dm));
485: PetscCall(DMGetLocalVector(dm, &Xloc));
486: PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
487: PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
488: PetscCall(DMDAGetLocalInfo(dm, &info));
489: PetscCall(DMDAVecGetArray(dm, Xloc, &x));
490: PetscCallBack("SNES Picard DMDA local callback Jacobian", (*dmdasnes->jacobianplocal)(&info, x, A, B, dmdasnes->picardlocalctx));
491: PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
492: PetscCall(DMRestoreLocalVector(dm, &Xloc));
493: if (A != B) {
494: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
495: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
496: }
497: PetscFunctionReturn(PETSC_SUCCESS);
498: }
500: /*@C
501: DMDASNESSetPicardLocal - set a local right hand side and matrix evaluation function for Picard iteration with `DMDA`
503: Logically Collective
505: Input Parameters:
506: + dm - `DM` to associate callback with
507: . imode - `INSERT_VALUES` if local function computes owned part, `ADD_VALUES` if it contributes to ghosted part
508: . func - local residual evaluation
509: . jac - function to compute Jacobian
510: - ctx - optional context for local residual evaluation
512: Calling sequence of `func`:
513: + info - defines the subdomain to evaluate the residual on
514: . x - dimensional pointer to state at which to evaluate residual
515: . f - dimensional pointer to residual, write the residual here
516: - ctx - optional context passed above
518: Calling sequence of `jac`:
519: + info - defines the subdomain to evaluate the residual on
520: . x - dimensional pointer to state at which to evaluate residual
521: . jac - the Jacobian
522: . Jp - approximation to the Jacobian used to compute the preconditioner, often `J`
523: - ctx - optional context passed above
525: Level: beginner
527: Note:
528: The user must use `SNESSetFunction`(`snes`,`NULL`,`SNESPicardComputeFunction`,&user));
529: in their code before calling this routine.
531: .seealso: [](ch_snes), `SNES`, `DMDA`, `DMSNESSetFunction()`, `DMDASNESSetJacobian()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`
532: @*/
533: PetscErrorCode DMDASNESSetPicardLocal(DM dm, InsertMode imode, PetscErrorCode (*func)(DMDALocalInfo *info, void *x, void *f, void *ctx), PetscErrorCode (*jac)(DMDALocalInfo *info, void *x, Mat jac, Mat Jp, void *ctx), void *ctx)
534: {
535: DMSNES sdm;
536: DMSNES_DA *dmdasnes;
538: PetscFunctionBegin;
540: PetscCall(DMGetDMSNESWrite(dm, &sdm));
541: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
543: dmdasnes->residuallocalimode = imode;
544: dmdasnes->rhsplocal = func;
545: dmdasnes->jacobianplocal = jac;
546: dmdasnes->picardlocalctx = ctx;
548: PetscCall(DMSNESSetPicard(dm, SNESComputePicard_DMDA, SNESComputePicardJacobian_DMDA, dmdasnes));
549: PetscCall(DMSNESSetMFFunction(dm, SNESComputeFunction_DMDA, dmdasnes));
550: PetscFunctionReturn(PETSC_SUCCESS);
551: }