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 function
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: Note:
308: The `J` and `M` matrices are created internally by `DMCreateMatrix()`
310: .seealso: [](ch_snes), `DMDA`, `DMDASNESSetFunctionLocal()`, `DMSNESSetJacobian()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`
311: @*/
312: PetscErrorCode DMDASNESSetJacobianLocal(DM dm, PetscErrorCode (*func)(DMDALocalInfo *info, void *x, Mat J, Mat M, void *ctx), void *ctx)
313: {
314: DMSNES sdm;
315: DMSNES_DA *dmdasnes;
317: PetscFunctionBegin;
319: PetscCall(DMGetDMSNESWrite(dm, &sdm));
320: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
322: dmdasnes->jacobianlocal = func;
323: dmdasnes->jacobianlocalctx = ctx;
325: PetscCall(DMSNESSetJacobian(dm, SNESComputeJacobian_DMDA, dmdasnes));
326: PetscFunctionReturn(PETSC_SUCCESS);
327: }
329: /*@C
330: DMDASNESSetJacobianLocalVec - set a local Jacobian evaluation function that operates on a local vector with `DMDA`
332: Logically Collective
334: Input Parameters:
335: + dm - `DM` to associate callback with
336: . func - local Jacobian evaluation
337: - ctx - optional context for local Jacobian evaluation
339: Calling sequence of `func`:
340: + info - `DMDALocalInfo` defining the subdomain to evaluate the Jacobian at
341: . x - state vector at which to evaluate Jacobian
342: . J - the Jacobian
343: . M - approximate Jacobian from which the preconditioner will be computed, often `J`
344: - ctx - optional context passed above
346: Level: beginner
348: .seealso: [](ch_snes), `DMDA`, `DMDASNESSetJacobianLocal()`, `DMDASNESSetFunctionLocalVec()`, `DMSNESSetJacobian()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`
349: @*/
350: PetscErrorCode DMDASNESSetJacobianLocalVec(DM dm, PetscErrorCode (*func)(DMDALocalInfo *info, Vec x, Mat J, Mat M, void *), void *ctx)
351: {
352: DMSNES sdm;
353: DMSNES_DA *dmdasnes;
355: PetscFunctionBegin;
357: PetscCall(DMGetDMSNESWrite(dm, &sdm));
358: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
360: dmdasnes->jacobianlocalvec = func;
361: dmdasnes->jacobianlocalctx = ctx;
363: PetscCall(DMSNESSetJacobian(dm, SNESComputeJacobian_DMDA, dmdasnes));
364: PetscFunctionReturn(PETSC_SUCCESS);
365: }
367: // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation
368: /*@C
369: DMDASNESSetObjectiveLocal - set a local residual evaluation function to used with a `DMDA`
371: Logically Collective
373: Input Parameters:
374: + dm - `DM` to associate callback with
375: . func - local objective evaluation, see `DMDASNESSetObjectiveLocal` for the calling sequence
376: - ctx - optional context for local residual evaluation
378: Level: beginner
380: .seealso: [](ch_snes), `DMDA`, `DMSNESSetFunction()`, `DMDASNESSetJacobianLocal()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMDASNESObjective`
381: @*/
382: PetscErrorCode DMDASNESSetObjectiveLocal(DM dm, DMDASNESObjective func, void *ctx)
383: {
384: DMSNES sdm;
385: DMSNES_DA *dmdasnes;
387: PetscFunctionBegin;
389: PetscCall(DMGetDMSNESWrite(dm, &sdm));
390: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
392: dmdasnes->objectivelocal = func;
393: dmdasnes->objectivelocalctx = ctx;
395: PetscCall(DMSNESSetObjective(dm, SNESComputeObjective_DMDA, dmdasnes));
396: PetscFunctionReturn(PETSC_SUCCESS);
397: }
399: // PetscClangLinter pragma disable: -fdoc-param-list-func-parameter-documentation
400: /*@C
401: DMDASNESSetObjectiveLocalVec - set a local residual evaluation function that operates on a local vector with `DMDA`
403: Logically Collective
405: Input Parameters:
406: + dm - `DM` to associate callback with
407: . func - local objective evaluation, see `DMDASNESSetObjectiveLocalVec` for the calling sequence
408: - ctx - optional context for local residual evaluation
410: Level: beginner
412: .seealso: [](ch_snes), `DMDA`, `DMDASNESSetObjectiveLocal()`, `DMSNESSetFunction()`, `DMDASNESSetJacobianLocalVec()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMDASNESObjectiveVec`
413: @*/
414: PetscErrorCode DMDASNESSetObjectiveLocalVec(DM dm, DMDASNESObjectiveVec func, void *ctx)
415: {
416: DMSNES sdm;
417: DMSNES_DA *dmdasnes;
419: PetscFunctionBegin;
421: PetscCall(DMGetDMSNESWrite(dm, &sdm));
422: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
424: dmdasnes->objectivelocalvec = func;
425: dmdasnes->objectivelocalctx = ctx;
427: PetscCall(DMSNESSetObjective(dm, SNESComputeObjective_DMDA, dmdasnes));
428: PetscFunctionReturn(PETSC_SUCCESS);
429: }
431: static PetscErrorCode SNESComputePicard_DMDA(SNES snes, Vec X, Vec F, void *ctx)
432: {
433: DM dm;
434: DMSNES_DA *dmdasnes = (DMSNES_DA *)ctx;
435: DMDALocalInfo info;
436: Vec Xloc;
437: void *x, *f;
439: PetscFunctionBegin;
443: PetscCheck(dmdasnes->rhsplocal, PetscObjectComm((PetscObject)snes), PETSC_ERR_PLIB, "Corrupt context");
444: PetscCall(SNESGetDM(snes, &dm));
445: PetscCall(DMGetLocalVector(dm, &Xloc));
446: PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
447: PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
448: PetscCall(DMDAGetLocalInfo(dm, &info));
449: PetscCall(DMDAVecGetArray(dm, Xloc, &x));
450: switch (dmdasnes->residuallocalimode) {
451: case INSERT_VALUES: {
452: PetscCall(DMDAVecGetArray(dm, F, &f));
453: PetscCallBack("SNES Picard DMDA local callback function", (*dmdasnes->rhsplocal)(&info, x, f, dmdasnes->picardlocalctx));
454: PetscCall(DMDAVecRestoreArray(dm, F, &f));
455: } break;
456: case ADD_VALUES: {
457: Vec Floc;
458: PetscCall(DMGetLocalVector(dm, &Floc));
459: PetscCall(VecZeroEntries(Floc));
460: PetscCall(DMDAVecGetArray(dm, Floc, &f));
461: PetscCallBack("SNES Picard DMDA local callback function", (*dmdasnes->rhsplocal)(&info, x, f, dmdasnes->picardlocalctx));
462: PetscCall(DMDAVecRestoreArray(dm, Floc, &f));
463: PetscCall(VecZeroEntries(F));
464: PetscCall(DMLocalToGlobalBegin(dm, Floc, ADD_VALUES, F));
465: PetscCall(DMLocalToGlobalEnd(dm, Floc, ADD_VALUES, F));
466: PetscCall(DMRestoreLocalVector(dm, &Floc));
467: } break;
468: default:
469: SETERRQ(PetscObjectComm((PetscObject)snes), PETSC_ERR_ARG_INCOMP, "Cannot use imode=%d", (int)dmdasnes->residuallocalimode);
470: }
471: PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
472: PetscCall(DMRestoreLocalVector(dm, &Xloc));
473: PetscFunctionReturn(PETSC_SUCCESS);
474: }
476: static PetscErrorCode SNESComputePicardJacobian_DMDA(SNES snes, Vec X, Mat A, Mat B, void *ctx)
477: {
478: DM dm;
479: DMSNES_DA *dmdasnes = (DMSNES_DA *)ctx;
480: DMDALocalInfo info;
481: Vec Xloc;
482: void *x;
484: PetscFunctionBegin;
485: PetscCheck(dmdasnes->jacobianplocal, PetscObjectComm((PetscObject)snes), PETSC_ERR_PLIB, "Corrupt context");
486: PetscCall(SNESGetDM(snes, &dm));
488: PetscCall(DMGetLocalVector(dm, &Xloc));
489: PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, Xloc));
490: PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, Xloc));
491: PetscCall(DMDAGetLocalInfo(dm, &info));
492: PetscCall(DMDAVecGetArray(dm, Xloc, &x));
493: PetscCallBack("SNES Picard DMDA local callback Jacobian", (*dmdasnes->jacobianplocal)(&info, x, A, B, dmdasnes->picardlocalctx));
494: PetscCall(DMDAVecRestoreArray(dm, Xloc, &x));
495: PetscCall(DMRestoreLocalVector(dm, &Xloc));
496: if (A != B) {
497: PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
498: PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
499: }
500: PetscFunctionReturn(PETSC_SUCCESS);
501: }
503: /*@C
504: DMDASNESSetPicardLocal - set a local right hand side and matrix evaluation function for Picard iteration with `DMDA`
506: Logically Collective
508: Input Parameters:
509: + dm - `DM` to associate callback with
510: . imode - `INSERT_VALUES` if local function computes owned part, `ADD_VALUES` if it contributes to ghosted part
511: . func - local residual evaluation
512: . jac - function to compute Jacobian
513: - ctx - optional context for local residual evaluation
515: Calling sequence of `func`:
516: + info - defines the subdomain to evaluate the residual on
517: . x - dimensional pointer to state at which to evaluate residual
518: . f - dimensional pointer to residual, write the residual here
519: - ctx - optional context passed above
521: Calling sequence of `jac`:
522: + info - defines the subdomain to evaluate the residual on
523: . x - dimensional pointer to state at which to evaluate residual
524: . jac - the Jacobian
525: . Jp - approximation to the Jacobian used to compute the preconditioner, often `J`
526: - ctx - optional context passed above
528: Level: beginner
530: Note:
531: The user must use `SNESSetFunction`(`snes`,`NULL`,`SNESPicardComputeFunction`,&user));
532: in their code before calling this routine.
534: .seealso: [](ch_snes), `SNES`, `DMDA`, `DMSNESSetFunction()`, `DMDASNESSetJacobian()`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`
535: @*/
536: 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)
537: {
538: DMSNES sdm;
539: DMSNES_DA *dmdasnes;
541: PetscFunctionBegin;
543: PetscCall(DMGetDMSNESWrite(dm, &sdm));
544: PetscCall(DMDASNESGetContext(dm, sdm, &dmdasnes));
546: dmdasnes->residuallocalimode = imode;
547: dmdasnes->rhsplocal = func;
548: dmdasnes->jacobianplocal = jac;
549: dmdasnes->picardlocalctx = ctx;
551: PetscCall(DMSNESSetPicard(dm, SNESComputePicard_DMDA, SNESComputePicardJacobian_DMDA, dmdasnes));
552: PetscCall(DMSNESSetMFFunction(dm, SNESComputeFunction_DMDA, dmdasnes));
553: PetscFunctionReturn(PETSC_SUCCESS);
554: }