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: }