Actual source code: dmsnes.c
1: #include <petsc/private/snesimpl.h>
2: #include <petsc/private/dmimpl.h>
4: static PetscErrorCode DMSNESUnsetFunctionContext_DMSNES(DMSNES sdm)
5: {
6: PetscFunctionBegin;
7: PetscCall(PetscObjectCompose((PetscObject)sdm, "function ctx", NULL));
8: sdm->functionctxcontainer = NULL;
9: PetscFunctionReturn(PETSC_SUCCESS);
10: }
12: static PetscErrorCode DMSNESUnsetJacobianContext_DMSNES(DMSNES sdm)
13: {
14: PetscFunctionBegin;
15: PetscCall(PetscObjectCompose((PetscObject)sdm, "jacobian ctx", NULL));
16: sdm->jacobianctxcontainer = NULL;
17: PetscFunctionReturn(PETSC_SUCCESS);
18: }
20: static PetscErrorCode DMSNESDestroy(DMSNES *kdm)
21: {
22: PetscFunctionBegin;
23: if (!*kdm) PetscFunctionReturn(PETSC_SUCCESS);
25: if (--((PetscObject)*kdm)->refct > 0) {
26: *kdm = NULL;
27: PetscFunctionReturn(PETSC_SUCCESS);
28: }
29: PetscCall(DMSNESUnsetFunctionContext_DMSNES(*kdm));
30: PetscCall(DMSNESUnsetJacobianContext_DMSNES(*kdm));
31: PetscTryTypeMethod(*kdm, destroy);
32: PetscCall(PetscHeaderDestroy(kdm));
33: PetscFunctionReturn(PETSC_SUCCESS);
34: }
36: PetscErrorCode DMSNESLoad(DMSNES kdm, PetscViewer viewer)
37: {
38: PetscFunctionBegin;
39: PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->computefunction, 1, NULL, PETSC_FUNCTION));
40: PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->computejacobian, 1, NULL, PETSC_FUNCTION));
41: PetscFunctionReturn(PETSC_SUCCESS);
42: }
44: PetscErrorCode DMSNESView(DMSNES kdm, PetscViewer viewer)
45: {
46: PetscBool isbinary;
48: PetscFunctionBegin;
49: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
50: if (isbinary) {
51: struct {
52: SNESFunctionFn *func;
53: } funcstruct;
54: struct {
55: SNESJacobianFn *jac;
56: } jacstruct;
57: funcstruct.func = kdm->ops->computefunction;
58: jacstruct.jac = kdm->ops->computejacobian;
59: PetscCall(PetscViewerBinaryWrite(viewer, &funcstruct, 1, PETSC_FUNCTION));
60: PetscCall(PetscViewerBinaryWrite(viewer, &jacstruct, 1, PETSC_FUNCTION));
61: }
62: PetscFunctionReturn(PETSC_SUCCESS);
63: }
65: static PetscErrorCode DMSNESCreate(MPI_Comm comm, DMSNES *kdm)
66: {
67: PetscFunctionBegin;
68: PetscCall(SNESInitializePackage());
69: PetscCall(PetscHeaderCreate(*kdm, DMSNES_CLASSID, "DMSNES", "DMSNES", "DMSNES", comm, DMSNESDestroy, DMSNESView));
70: PetscFunctionReturn(PETSC_SUCCESS);
71: }
73: /* Attaches the DMSNES to the coarse level.
74: * Under what conditions should we copy versus duplicate?
75: */
76: static PetscErrorCode DMCoarsenHook_DMSNES(DM dm, DM dmc, PetscCtx ctx)
77: {
78: PetscFunctionBegin;
79: PetscCall(DMCopyDMSNES(dm, dmc));
80: PetscFunctionReturn(PETSC_SUCCESS);
81: }
83: /* This could restrict auxiliary information to the coarse level.
84: */
85: static PetscErrorCode DMRestrictHook_DMSNES(DM dm, Mat Restrict, Vec rscale, Mat Inject, DM dmc, PetscCtx ctx)
86: {
87: PetscFunctionBegin;
88: PetscFunctionReturn(PETSC_SUCCESS);
89: }
91: /* Attaches the DMSNES to the subdomain. */
92: static PetscErrorCode DMSubDomainHook_DMSNES(DM dm, DM subdm, PetscCtx ctx)
93: {
94: PetscFunctionBegin;
95: PetscCall(DMCopyDMSNES(dm, subdm));
96: PetscFunctionReturn(PETSC_SUCCESS);
97: }
99: /* This could restrict auxiliary information to the coarse level.
100: */
101: static PetscErrorCode DMSubDomainRestrictHook_DMSNES(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, PetscCtx ctx)
102: {
103: PetscFunctionBegin;
104: PetscFunctionReturn(PETSC_SUCCESS);
105: }
107: static PetscErrorCode DMRefineHook_DMSNES(DM dm, DM dmf, PetscCtx ctx)
108: {
109: PetscFunctionBegin;
110: PetscCall(DMCopyDMSNES(dm, dmf));
111: PetscFunctionReturn(PETSC_SUCCESS);
112: }
114: /* This could restrict auxiliary information to the coarse level.
115: */
116: static PetscErrorCode DMInterpolateHook_DMSNES(DM dm, Mat Interp, DM dmf, PetscCtx ctx)
117: {
118: PetscFunctionBegin;
119: PetscFunctionReturn(PETSC_SUCCESS);
120: }
122: /*
123: DMSNESCopy - copies the information in a `DMSNES` to another `DMSNES`
125: Not Collective
127: Input Parameters:
128: + kdm - Original `DMSNES`
129: - nkdm - `DMSNES` to receive the data, should have been created with `DMSNESCreate()`
131: Level: developer
133: .seealso: [](ch_snes), `DMSNES`, `DMSNESCreate()`, `DMSNESDestroy()`
134: */
135: static PetscErrorCode DMSNESCopy(DMSNES kdm, DMSNES nkdm)
136: {
137: PetscFunctionBegin;
140: nkdm->ops->computefunction = kdm->ops->computefunction;
141: nkdm->ops->computejacobian = kdm->ops->computejacobian;
142: nkdm->ops->computegs = kdm->ops->computegs;
143: nkdm->ops->computeobjective = kdm->ops->computeobjective;
144: nkdm->ops->computepjacobian = kdm->ops->computepjacobian;
145: nkdm->ops->computepfunction = kdm->ops->computepfunction;
146: nkdm->ops->destroy = kdm->ops->destroy;
147: nkdm->ops->duplicate = kdm->ops->duplicate;
149: nkdm->gsctx = kdm->gsctx;
150: nkdm->pctx = kdm->pctx;
151: nkdm->objectivectx = kdm->objectivectx;
152: nkdm->originaldm = kdm->originaldm;
153: nkdm->functionctxcontainer = kdm->functionctxcontainer;
154: nkdm->jacobianctxcontainer = kdm->jacobianctxcontainer;
155: if (nkdm->functionctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "function ctx", (PetscObject)nkdm->functionctxcontainer));
156: if (nkdm->jacobianctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "jacobian ctx", (PetscObject)nkdm->jacobianctxcontainer));
158: /*
159: nkdm->fortran_func_pointers[0] = kdm->fortran_func_pointers[0];
160: nkdm->fortran_func_pointers[1] = kdm->fortran_func_pointers[1];
161: nkdm->fortran_func_pointers[2] = kdm->fortran_func_pointers[2];
162: */
164: /* implementation specific copy hooks */
165: PetscTryTypeMethod(kdm, duplicate, nkdm);
166: PetscFunctionReturn(PETSC_SUCCESS);
167: }
169: /*@
170: DMGetDMSNES - get read-only private `DMSNES` context from a `DM`
172: Not Collective
174: Input Parameter:
175: . dm - `DM` to be used with `SNES`
177: Output Parameter:
178: . snesdm - private `DMSNES` context
180: Level: developer
182: Note:
183: Use `DMGetDMSNESWrite()` if write access is needed. The DMSNESSetXXX API should be used wherever possible.
185: .seealso: [](ch_snes), `DMSNES`, `DMGetDMSNESWrite()`
186: @*/
187: PetscErrorCode DMGetDMSNES(DM dm, DMSNES *snesdm)
188: {
189: PetscFunctionBegin;
191: *snesdm = (DMSNES)dm->dmsnes;
192: if (!*snesdm) {
193: PetscCall(PetscInfo(dm, "Creating new DMSNES\n"));
194: PetscCall(DMSNESCreate(PetscObjectComm((PetscObject)dm), snesdm));
196: dm->dmsnes = (PetscObject)*snesdm;
197: (*snesdm)->originaldm = dm;
198: PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_DMSNES, DMRestrictHook_DMSNES, NULL));
199: PetscCall(DMRefineHookAdd(dm, DMRefineHook_DMSNES, DMInterpolateHook_DMSNES, NULL));
200: PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_DMSNES, DMSubDomainRestrictHook_DMSNES, NULL));
201: }
202: PetscFunctionReturn(PETSC_SUCCESS);
203: }
205: /*@
206: DMGetDMSNESWrite - get write access to private `DMSNES` context from a `DM`
208: Not Collective
210: Input Parameter:
211: . dm - `DM` to be used with `SNES`
213: Output Parameter:
214: . snesdm - private `DMSNES` context
216: Level: developer
218: .seealso: [](ch_snes), `DMSNES`, `DMGetDMSNES()`
219: @*/
220: PetscErrorCode DMGetDMSNESWrite(DM dm, DMSNES *snesdm)
221: {
222: DMSNES sdm;
224: PetscFunctionBegin;
226: PetscCall(DMGetDMSNES(dm, &sdm));
227: PetscCheck(sdm->originaldm, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DMSNES has a NULL originaldm");
228: if (sdm->originaldm != dm) { /* Copy on write */
229: DMSNES oldsdm = sdm;
230: PetscCall(PetscInfo(dm, "Copying DMSNES due to write\n"));
231: PetscCall(DMSNESCreate(PetscObjectComm((PetscObject)dm), &sdm));
232: PetscCall(DMSNESCopy(oldsdm, sdm));
233: PetscCall(DMSNESDestroy((DMSNES *)&dm->dmsnes));
234: dm->dmsnes = (PetscObject)sdm;
235: sdm->originaldm = dm;
236: }
237: *snesdm = sdm;
238: PetscFunctionReturn(PETSC_SUCCESS);
239: }
241: /*@
242: DMCopyDMSNES - copies a `DMSNES` context to a new `DM`
244: Logically Collective
246: Input Parameters:
247: + dmsrc - `DM` to obtain context from
248: - dmdest - `DM` to add context to
250: Level: developer
252: Note:
253: The context is copied by reference. This function does not ensure that a context exists.
255: .seealso: [](ch_snes), `DMSNES`, `DMGetDMSNES()`, `SNESSetDM()`
256: @*/
257: PetscErrorCode DMCopyDMSNES(DM dmsrc, DM dmdest)
258: {
259: PetscFunctionBegin;
262: if (!dmdest->dmsnes) PetscCall(DMSNESCreate(PetscObjectComm((PetscObject)dmdest), (DMSNES *)&dmdest->dmsnes));
263: PetscCall(DMSNESCopy((DMSNES)dmsrc->dmsnes, (DMSNES)dmdest->dmsnes));
264: PetscCall(DMCoarsenHookAdd(dmdest, DMCoarsenHook_DMSNES, NULL, NULL));
265: PetscCall(DMRefineHookAdd(dmdest, DMRefineHook_DMSNES, NULL, NULL));
266: PetscCall(DMSubDomainHookAdd(dmdest, DMSubDomainHook_DMSNES, DMSubDomainRestrictHook_DMSNES, NULL));
267: PetscFunctionReturn(PETSC_SUCCESS);
268: }
270: /*@
271: DMSNESSetFunction - set `SNES` residual evaluation function
273: Not Collective
275: Input Parameters:
276: + dm - DM to be used with `SNES`
277: . f - residual evaluation function; see `SNESFunctionFn` for calling sequence
278: - ctx - context for residual evaluation
280: Level: developer
282: Note:
283: `SNESSetFunction()` is normally used, but it calls this function internally because the application context is actually
284: associated with the `DM`. This makes the interface consistent regardless of whether the user interacts with a `DM` or
285: not.
286: If both `f` and `ctx` are `NULL`, it removes the callback.
288: Developer Note:
289: If `DM` took a more central role at some later date, this could become the primary method of setting the residual.
291: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `SNESFunctionFn`
292: @*/
293: PetscErrorCode DMSNESSetFunction(DM dm, SNESFunctionFn *f, PetscCtx ctx)
294: {
295: DMSNES sdm;
297: PetscFunctionBegin;
299: PetscCall(DMGetDMSNESWrite(dm, &sdm));
300: if (f) sdm->ops->computefunction = f;
301: if (ctx) {
302: PetscContainer ctxcontainer;
303: PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)sdm), &ctxcontainer));
304: PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
305: PetscCall(PetscObjectCompose((PetscObject)sdm, "function ctx", (PetscObject)ctxcontainer));
306: sdm->functionctxcontainer = ctxcontainer;
307: PetscCall(PetscContainerDestroy(&ctxcontainer));
308: }
309: if (!f && !ctx) {
310: sdm->ops->computefunction = NULL;
311: PetscCall(DMSNESUnsetFunctionContext_DMSNES(sdm));
312: }
313: PetscFunctionReturn(PETSC_SUCCESS);
314: }
316: /*@
317: DMSNESSetFunctionContextDestroy - set `SNES` residual evaluation context destroy function
319: Not Collective
321: Input Parameters:
322: + dm - `DM` to be used with `SNES`
323: - f - residual evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence
325: Level: developer
327: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetFunction()`, `SNESSetFunction()`, `PetscCtxDestroyFn`
328: @*/
329: PetscErrorCode DMSNESSetFunctionContextDestroy(DM dm, PetscCtxDestroyFn *f)
330: {
331: DMSNES sdm;
333: PetscFunctionBegin;
335: PetscCall(DMGetDMSNESWrite(dm, &sdm));
336: if (sdm->functionctxcontainer) PetscCall(PetscContainerSetCtxDestroy(sdm->functionctxcontainer, f));
337: PetscFunctionReturn(PETSC_SUCCESS);
338: }
340: PetscErrorCode DMSNESUnsetFunctionContext_Internal(DM dm)
341: {
342: DMSNES sdm;
344: PetscFunctionBegin;
346: PetscCall(DMGetDMSNESWrite(dm, &sdm));
347: PetscCall(DMSNESUnsetFunctionContext_DMSNES(sdm));
348: PetscFunctionReturn(PETSC_SUCCESS);
349: }
351: /*@
352: DMSNESSetMFFunction - set `SNES` residual evaluation function used in applying the matrix-free Jacobian with `-snes_mf_operator`
354: Logically Collective
356: Input Parameters:
357: + dm - `DM` to be used with `SNES`
358: . func - residual evaluation function; see `SNESFunctionFn` for calling sequence
359: - ctx - optional function context
361: Level: developer
363: Note:
364: If not provided then the function provided with `SNESSetFunction()` is used.
365: If both `func` and `ctx` are `NULL`, it removes the callback.
367: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `DMSNESSetFunction()`, `SNESFunctionFn`
368: @*/
369: PetscErrorCode DMSNESSetMFFunction(DM dm, SNESFunctionFn *func, PetscCtx ctx)
370: {
371: DMSNES sdm;
373: PetscFunctionBegin;
375: PetscCall(DMGetDMSNESWrite(dm, &sdm));
376: if (func) sdm->ops->computemffunction = func;
377: if (ctx) sdm->mffunctionctx = ctx;
378: if (!func && !ctx) {
379: sdm->ops->computemffunction = NULL;
380: sdm->mffunctionctx = NULL;
381: }
382: PetscFunctionReturn(PETSC_SUCCESS);
383: }
385: /*@
386: DMSNESGetFunction - get `SNES` residual evaluation function from a `DMSNES` object
388: Not Collective
390: Input Parameter:
391: . dm - `DM` to be used with `SNES`
393: Output Parameters:
394: + f - residual evaluation function; see `SNESFunctionFn` for calling sequence
395: - ctx - context for residual evaluation
397: Level: developer
399: Note:
400: `SNESGetFunction()` is normally used, but it calls this function internally because the application context is actually
401: associated with the `DM`.
403: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `DMSNESSetFunction()`, `SNESSetFunction()`, `SNESFunctionFn`
404: @*/
405: PetscErrorCode DMSNESGetFunction(DM dm, SNESFunctionFn **f, PetscCtxRt ctx)
406: {
407: DMSNES sdm;
409: PetscFunctionBegin;
411: PetscCall(DMGetDMSNES(dm, &sdm));
412: if (f) *f = sdm->ops->computefunction;
413: if (ctx) {
414: if (sdm->functionctxcontainer) PetscCall(PetscContainerGetPointer(sdm->functionctxcontainer, ctx));
415: else *(void **)ctx = NULL;
416: }
417: PetscFunctionReturn(PETSC_SUCCESS);
418: }
420: /*@
421: DMSNESSetObjective - Sets the objective function minimized by some of the `SNES` linesearch methods into a `DMSNES` object, used instead of the 2-norm of the residual
423: Not Collective
425: Input Parameters:
426: + dm - `DM` to be used with `SNES`
427: . obj - objective evaluation routine; see `SNESObjectiveFn` for the calling sequence
428: - ctx - [optional] user-defined context for private data for the objective evaluation routine (may be `NULL`)
430: Level: developer
432: Note:
433: If both `obj` and `ctx` are `NULL`, it removes the callback.
435: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESGetObjective()`, `DMSNESSetFunction()`, `SNESObjectiveFn`
436: @*/
437: PetscErrorCode DMSNESSetObjective(DM dm, SNESObjectiveFn *obj, PetscCtx ctx)
438: {
439: DMSNES sdm;
441: PetscFunctionBegin;
443: PetscCall(DMGetDMSNESWrite(dm, &sdm));
444: if (obj) sdm->ops->computeobjective = obj;
445: if (ctx) sdm->objectivectx = ctx;
446: if (!obj && !ctx) {
447: sdm->ops->computeobjective = NULL;
448: sdm->objectivectx = NULL;
449: }
450: PetscFunctionReturn(PETSC_SUCCESS);
451: }
453: /*@
454: DMSNESGetObjective - Returns the objective function set with `DMSNESSetObjective()`
456: Not Collective
458: Input Parameter:
459: . dm - `DM` to be used with `SNES`
461: Output Parameters:
462: + obj - objective evaluation routine (or `NULL`); see `SNESObjectiveFn` for the calling sequence
463: - ctx - the function context (or `NULL`)
465: Level: developer
467: Note:
468: `SNESGetFunction()` is normally used, but it calls this function internally because the application context is actually
469: associated with the `DM`.
471: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `DMSNESSetObjective()`, `SNESSetFunction()`, `SNESObjectiveFn`
472: @*/
473: PetscErrorCode DMSNESGetObjective(DM dm, SNESObjectiveFn **obj, PetscCtxRt ctx)
474: {
475: DMSNES sdm;
477: PetscFunctionBegin;
479: PetscCall(DMGetDMSNES(dm, &sdm));
480: if (obj) *obj = sdm->ops->computeobjective;
481: if (ctx) *(void **)ctx = sdm->objectivectx;
482: PetscFunctionReturn(PETSC_SUCCESS);
483: }
485: /*@
486: DMSNESSetNGS - set `SNES` Gauss-Seidel relaxation function into a `DMSNES` object
488: Not Collective
490: Input Parameters:
491: + dm - `DM` to be used with `SNES`
492: . f - relaxation function, see `SNESGSFunction`
493: - ctx - context for residual evaluation
495: Level: developer
497: Note:
498: `SNESSetNGS()` is normally used, but it calls this function internally because the application context is actually
499: associated with the `DM`. This makes the interface consistent regardless of whether the user interacts with a `DM` or
500: not.
501: If both `f` and `ctx` are `NULL`, it removes the callback.
503: Developer Note:
504: If `DM` took a more central role at some later date, this could become the primary method of supplying the smoother
506: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `DMSNESSetFunction()`, `SNESGSFunction`
507: @*/
508: PetscErrorCode DMSNESSetNGS(DM dm, PetscErrorCode (*f)(SNES, Vec, Vec, void *), PetscCtx ctx)
509: {
510: DMSNES sdm;
512: PetscFunctionBegin;
514: PetscCall(DMGetDMSNESWrite(dm, &sdm));
515: if (f) sdm->ops->computegs = f;
516: if (ctx) sdm->gsctx = ctx;
517: if (!f && !ctx) {
518: sdm->ops->computegs = NULL;
519: sdm->gsctx = NULL;
520: }
521: PetscFunctionReturn(PETSC_SUCCESS);
522: }
524: /*@
525: DMSNESGetNGS - get `SNES` Gauss-Seidel relaxation function from a `DMSNES` object
527: Not Collective
529: Input Parameter:
530: . dm - `DM` to be used with `SNES`
532: Output Parameters:
533: + f - relaxation function which performs Gauss-Seidel sweeps, see `SNESSetNGS()`
534: - ctx - context for residual evaluation
536: Level: developer
538: Note:
539: `SNESGetNGS()` is normally used, but it calls this function internally because the application context is actually
540: associated with the `DM`.
542: Developer Note:
543: This makes the interface consistent regardless of whether the user interacts with a `DM` or
544: not. If `DM` took a more central role at some later date, this could become the primary method of setting the residual.
546: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESGetNGS()`, `DMSNESGetJacobian()`, `DMSNESGetFunction()`
547: @*/
548: PetscErrorCode DMSNESGetNGS(DM dm, PetscErrorCode (**f)(SNES, Vec, Vec, void *), PetscCtxRt ctx)
549: {
550: DMSNES sdm;
552: PetscFunctionBegin;
554: PetscCall(DMGetDMSNES(dm, &sdm));
555: if (f) *f = sdm->ops->computegs;
556: if (ctx) *(void **)ctx = sdm->gsctx;
557: PetscFunctionReturn(PETSC_SUCCESS);
558: }
560: /*@
561: DMSNESSetJacobian - set `SNES` Jacobian evaluation function into a `DMSNES` object
563: Not Collective
565: Input Parameters:
566: + dm - `DM` to be used with `SNES`
567: . J - Jacobian evaluation function, see `SNESJacobianFn`
568: - ctx - context for Jacobian evaluation
570: Level: developer
572: Note:
573: `SNESSetJacobian()` is normally used, but it calls this function internally because the application context is actually
574: associated with the `DM`.
575: If both `J` and `ctx` are `NULL`, it removes the callback.
577: Developer Note:
578: This makes the interface consistent regardless of whether the user interacts with a `DM` or
579: not. If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian.
581: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESGetJacobian()`, `SNESSetJacobian()`, `SNESJacobianFn`
582: @*/
583: PetscErrorCode DMSNESSetJacobian(DM dm, SNESJacobianFn *J, PetscCtx ctx)
584: {
585: DMSNES sdm;
587: PetscFunctionBegin;
589: PetscCall(DMGetDMSNESWrite(dm, &sdm));
590: if (J) sdm->ops->computejacobian = J;
591: if (ctx) {
592: PetscContainer ctxcontainer;
593: PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)sdm), &ctxcontainer));
594: PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
595: PetscCall(PetscObjectCompose((PetscObject)sdm, "jacobian ctx", (PetscObject)ctxcontainer));
596: sdm->jacobianctxcontainer = ctxcontainer;
597: PetscCall(PetscContainerDestroy(&ctxcontainer));
598: }
599: if (!J && !ctx) {
600: sdm->ops->computejacobian = NULL;
601: PetscCall(DMSNESUnsetJacobianContext_DMSNES(sdm));
602: }
603: PetscFunctionReturn(PETSC_SUCCESS);
604: }
606: /*@
607: DMSNESSetJacobianContextDestroy - set `SNES` Jacobian evaluation context destroy function into a `DMSNES` object
609: Not Collective
611: Input Parameters:
612: + dm - `DM` to be used with `SNES`
613: - f - Jacobian evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence
615: Level: developer
617: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetJacobian()`
618: @*/
619: PetscErrorCode DMSNESSetJacobianContextDestroy(DM dm, PetscCtxDestroyFn *f)
620: {
621: DMSNES sdm;
623: PetscFunctionBegin;
625: PetscCall(DMGetDMSNESWrite(dm, &sdm));
626: if (sdm->jacobianctxcontainer) PetscCall(PetscContainerSetCtxDestroy(sdm->jacobianctxcontainer, f));
627: PetscFunctionReturn(PETSC_SUCCESS);
628: }
630: PetscErrorCode DMSNESUnsetJacobianContext_Internal(DM dm)
631: {
632: DMSNES sdm;
634: PetscFunctionBegin;
636: PetscCall(DMGetDMSNESWrite(dm, &sdm));
637: PetscCall(DMSNESUnsetJacobianContext_DMSNES(sdm));
638: PetscFunctionReturn(PETSC_SUCCESS);
639: }
641: /*@
642: DMSNESGetJacobian - get `SNES` Jacobian evaluation function from a `DMSNES` object
644: Not Collective
646: Input Parameter:
647: . dm - `DM` to be used with `SNES`
649: Output Parameters:
650: + J - Jacobian evaluation function; for all calling sequence see `SNESJacobianFn`
651: - ctx - context for residual evaluation
653: Level: developer
655: Note:
656: `SNESGetJacobian()` is normally used, but it calls this function internally because the application context is actually
657: associated with the `DM`. This makes the interface consistent regardless of whether the user interacts with a `DM` or
658: not.
660: Developer Note:
661: If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian.
663: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `SNESJacobianFn`
664: @*/
665: PetscErrorCode DMSNESGetJacobian(DM dm, SNESJacobianFn **J, PetscCtxRt ctx)
666: {
667: DMSNES sdm;
669: PetscFunctionBegin;
671: PetscCall(DMGetDMSNES(dm, &sdm));
672: if (J) *J = sdm->ops->computejacobian;
673: if (ctx) {
674: if (sdm->jacobianctxcontainer) PetscCall(PetscContainerGetPointer(sdm->jacobianctxcontainer, ctx));
675: else *(void **)ctx = NULL;
676: }
677: PetscFunctionReturn(PETSC_SUCCESS);
678: }
680: /*@
681: DMSNESSetPicard - set SNES Picard iteration matrix and RHS evaluation functions into a `DMSNES` object
683: Not Collective
685: Input Parameters:
686: + dm - `DM` to be used with `SNES`
687: . b - RHS evaluation function; see `SNESFunctionFn` for calling sequence
688: . J - Picard matrix evaluation function; see `SNESJacobianFn` for calling sequence
689: - ctx - context for residual and matrix evaluation
691: Level: developer
693: .seealso: [](ch_snes), `DMSNES`, `SNESSetPicard()`, `DMSNESSetFunction()`, `DMSNESSetJacobian()`, `SNESFunctionFn`, `SNESJacobianFn`
694: @*/
695: PetscErrorCode DMSNESSetPicard(DM dm, SNESFunctionFn *b, SNESJacobianFn *J, PetscCtx ctx)
696: {
697: DMSNES sdm;
699: PetscFunctionBegin;
701: PetscCall(DMGetDMSNES(dm, &sdm));
702: if (b) sdm->ops->computepfunction = b;
703: if (J) sdm->ops->computepjacobian = J;
704: if (ctx) sdm->pctx = ctx;
705: PetscFunctionReturn(PETSC_SUCCESS);
706: }
708: /*@
709: DMSNESGetPicard - get `SNES` Picard iteration evaluation functions from a `DMSNES` object
711: Not Collective
713: Input Parameter:
714: . dm - `DM` to be used with `SNES`
716: Output Parameters:
717: + b - RHS evaluation function; see `SNESFunctionFn` for calling sequence
718: . J - Jacobian evaluation function; see `SNESJacobianFn` for calling sequence
719: - ctx - context for residual and matrix evaluation
721: Level: developer
723: .seealso: [](ch_snes), `DMSNES`, `DMSNESSetContext()`, `SNESSetFunction()`, `DMSNESSetJacobian()`, `SNESFunctionFn`, `SNESJacobianFn`
724: @*/
725: PetscErrorCode DMSNESGetPicard(DM dm, SNESFunctionFn **b, SNESJacobianFn **J, PetscCtxRt ctx)
726: {
727: DMSNES sdm;
729: PetscFunctionBegin;
731: PetscCall(DMGetDMSNES(dm, &sdm));
732: if (b) *b = sdm->ops->computepfunction;
733: if (J) *J = sdm->ops->computepjacobian;
734: if (ctx) *(void **)ctx = sdm->pctx;
735: PetscFunctionReturn(PETSC_SUCCESS);
736: }