Actual source code: dmts.c

  1: #include <petsc/private/tsimpl.h>
  2: #include <petsc/private/dmimpl.h>

  4: static PetscErrorCode DMTSUnsetRHSFunctionContext_DMTS(DMTS tsdm)
  5: {
  6:   PetscFunctionBegin;
  7:   PetscCall(PetscObjectCompose((PetscObject)tsdm, "rhs function ctx", NULL));
  8:   tsdm->rhsfunctionctxcontainer = NULL;
  9:   PetscFunctionReturn(PETSC_SUCCESS);
 10: }

 12: static PetscErrorCode DMTSUnsetRHSJacobianContext_DMTS(DMTS tsdm)
 13: {
 14:   PetscFunctionBegin;
 15:   PetscCall(PetscObjectCompose((PetscObject)tsdm, "rhs jacobian ctx", NULL));
 16:   tsdm->rhsjacobianctxcontainer = NULL;
 17:   PetscFunctionReturn(PETSC_SUCCESS);
 18: }

 20: static PetscErrorCode DMTSUnsetIFunctionContext_DMTS(DMTS tsdm)
 21: {
 22:   PetscFunctionBegin;
 23:   PetscCall(PetscObjectCompose((PetscObject)tsdm, "ifunction ctx", NULL));
 24:   tsdm->ifunctionctxcontainer = NULL;
 25:   PetscFunctionReturn(PETSC_SUCCESS);
 26: }

 28: static PetscErrorCode DMTSUnsetIJacobianContext_DMTS(DMTS tsdm)
 29: {
 30:   PetscFunctionBegin;
 31:   PetscCall(PetscObjectCompose((PetscObject)tsdm, "ijacobian ctx", NULL));
 32:   tsdm->ijacobianctxcontainer = NULL;
 33:   PetscFunctionReturn(PETSC_SUCCESS);
 34: }

 36: static PetscErrorCode DMTSUnsetI2FunctionContext_DMTS(DMTS tsdm)
 37: {
 38:   PetscFunctionBegin;
 39:   PetscCall(PetscObjectCompose((PetscObject)tsdm, "i2function ctx", NULL));
 40:   tsdm->i2functionctxcontainer = NULL;
 41:   PetscFunctionReturn(PETSC_SUCCESS);
 42: }

 44: static PetscErrorCode DMTSUnsetI2JacobianContext_DMTS(DMTS tsdm)
 45: {
 46:   PetscFunctionBegin;
 47:   PetscCall(PetscObjectCompose((PetscObject)tsdm, "i2jacobian ctx", NULL));
 48:   tsdm->i2jacobianctxcontainer = NULL;
 49:   PetscFunctionReturn(PETSC_SUCCESS);
 50: }

 52: static PetscErrorCode DMTSDestroy(DMTS *kdm)
 53: {
 54:   PetscFunctionBegin;
 55:   if (!*kdm) PetscFunctionReturn(PETSC_SUCCESS);
 57:   if (--((PetscObject)*kdm)->refct > 0) {
 58:     *kdm = NULL;
 59:     PetscFunctionReturn(PETSC_SUCCESS);
 60:   }
 61:   PetscCall(DMTSUnsetRHSFunctionContext_DMTS(*kdm));
 62:   PetscCall(DMTSUnsetRHSJacobianContext_DMTS(*kdm));
 63:   PetscCall(DMTSUnsetIFunctionContext_DMTS(*kdm));
 64:   PetscCall(DMTSUnsetIJacobianContext_DMTS(*kdm));
 65:   PetscCall(DMTSUnsetI2FunctionContext_DMTS(*kdm));
 66:   PetscCall(DMTSUnsetI2JacobianContext_DMTS(*kdm));
 67:   PetscTryTypeMethod(*kdm, destroy);
 68:   PetscCall(PetscHeaderDestroy(kdm));
 69:   PetscFunctionReturn(PETSC_SUCCESS);
 70: }

 72: PetscErrorCode DMTSLoad(DMTS kdm, PetscViewer viewer)
 73: {
 74:   PetscFunctionBegin;
 75:   PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->ifunction, 1, NULL, PETSC_FUNCTION));
 76:   PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->ifunctionview, 1, NULL, PETSC_FUNCTION));
 77:   PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->ifunctionload, 1, NULL, PETSC_FUNCTION));
 78:   if (kdm->ops->ifunctionload) {
 79:     void *ctx;

 81:     PetscCall(PetscContainerGetPointer(kdm->ifunctionctxcontainer, &ctx));
 82:     PetscCall((*kdm->ops->ifunctionload)(&ctx, viewer));
 83:   }
 84:   PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->ijacobian, 1, NULL, PETSC_FUNCTION));
 85:   PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->ijacobianview, 1, NULL, PETSC_FUNCTION));
 86:   PetscCall(PetscViewerBinaryRead(viewer, &kdm->ops->ijacobianload, 1, NULL, PETSC_FUNCTION));
 87:   if (kdm->ops->ijacobianload) {
 88:     void *ctx;

 90:     PetscCall(PetscContainerGetPointer(kdm->ijacobianctxcontainer, &ctx));
 91:     PetscCall((*kdm->ops->ijacobianload)(&ctx, viewer));
 92:   }
 93:   PetscFunctionReturn(PETSC_SUCCESS);
 94: }

 96: PetscErrorCode DMTSView(DMTS kdm, PetscViewer viewer)
 97: {
 98:   PetscBool isascii, isbinary;

100:   PetscFunctionBegin;
101:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
102:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
103:   if (isascii) {
104: #if defined(PETSC_SERIALIZE_FUNCTIONS)
105:     const char *fname;

107:     PetscCall(PetscFPTFind(kdm->ops->ifunction, &fname));
108:     if (fname) PetscCall(PetscViewerASCIIPrintf(viewer, "  IFunction used by TS: %s\n", fname));
109:     PetscCall(PetscFPTFind(kdm->ops->ijacobian, &fname));
110:     if (fname) PetscCall(PetscViewerASCIIPrintf(viewer, "  IJacobian function used by TS: %s\n", fname));
111: #endif
112:   } else if (isbinary) {
113:     struct {
114:       TSIFunctionFn *ifunction;
115:     } funcstruct;
116:     struct {
117:       PetscErrorCode (*ifunctionview)(void *, PetscViewer);
118:     } funcviewstruct;
119:     struct {
120:       PetscErrorCode (*ifunctionload)(void **, PetscViewer);
121:     } funcloadstruct;
122:     struct {
123:       TSIJacobianFn *ijacobian;
124:     } jacstruct;
125:     struct {
126:       PetscErrorCode (*ijacobianview)(void *, PetscViewer);
127:     } jacviewstruct;
128:     struct {
129:       PetscErrorCode (*ijacobianload)(void **, PetscViewer);
130:     } jacloadstruct;

132:     funcstruct.ifunction         = kdm->ops->ifunction;
133:     funcviewstruct.ifunctionview = kdm->ops->ifunctionview;
134:     funcloadstruct.ifunctionload = kdm->ops->ifunctionload;
135:     PetscCall(PetscViewerBinaryWrite(viewer, &funcstruct, 1, PETSC_FUNCTION));
136:     PetscCall(PetscViewerBinaryWrite(viewer, &funcviewstruct, 1, PETSC_FUNCTION));
137:     PetscCall(PetscViewerBinaryWrite(viewer, &funcloadstruct, 1, PETSC_FUNCTION));
138:     if (kdm->ops->ifunctionview) {
139:       void *ctx;

141:       PetscCall(PetscContainerGetPointer(kdm->ifunctionctxcontainer, &ctx));
142:       PetscCall((*kdm->ops->ifunctionview)(ctx, viewer));
143:     }
144:     jacstruct.ijacobian         = kdm->ops->ijacobian;
145:     jacviewstruct.ijacobianview = kdm->ops->ijacobianview;
146:     jacloadstruct.ijacobianload = kdm->ops->ijacobianload;
147:     PetscCall(PetscViewerBinaryWrite(viewer, &jacstruct, 1, PETSC_FUNCTION));
148:     PetscCall(PetscViewerBinaryWrite(viewer, &jacviewstruct, 1, PETSC_FUNCTION));
149:     PetscCall(PetscViewerBinaryWrite(viewer, &jacloadstruct, 1, PETSC_FUNCTION));
150:     if (kdm->ops->ijacobianview) {
151:       void *ctx;

153:       PetscCall(PetscContainerGetPointer(kdm->ijacobianctxcontainer, &ctx));
154:       PetscCall((*kdm->ops->ijacobianview)(ctx, viewer));
155:     }
156:   }
157:   PetscFunctionReturn(PETSC_SUCCESS);
158: }

160: static PetscErrorCode DMTSCreate(MPI_Comm comm, DMTS *kdm)
161: {
162:   PetscFunctionBegin;
163:   PetscCall(TSInitializePackage());
164:   PetscCall(PetscHeaderCreate(*kdm, DMTS_CLASSID, "DMTS", "DMTS", "DMTS", comm, DMTSDestroy, DMTSView));
165:   PetscFunctionReturn(PETSC_SUCCESS);
166: }

168: /* Attaches the DMTS to the coarse level.
169:  * Under what conditions should we copy versus duplicate?
170:  */
171: static PetscErrorCode DMCoarsenHook_DMTS(DM dm, DM dmc, void *ctx)
172: {
173:   PetscFunctionBegin;
174:   PetscCall(DMCopyDMTS(dm, dmc));
175:   PetscFunctionReturn(PETSC_SUCCESS);
176: }

178: /* This could restrict auxiliary information to the coarse level.
179:  */
180: static PetscErrorCode DMRestrictHook_DMTS(DM dm, Mat Restrict, Vec rscale, Mat Inject, DM dmc, void *ctx)
181: {
182:   PetscFunctionBegin;
183:   PetscFunctionReturn(PETSC_SUCCESS);
184: }

186: static PetscErrorCode DMSubDomainHook_DMTS(DM dm, DM subdm, void *ctx)
187: {
188:   PetscFunctionBegin;
189:   PetscCall(DMCopyDMTS(dm, subdm));
190:   PetscFunctionReturn(PETSC_SUCCESS);
191: }

193: /* This could restrict auxiliary information to the coarse level.
194:  */
195: static PetscErrorCode DMSubDomainRestrictHook_DMTS(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
196: {
197:   PetscFunctionBegin;
198:   PetscFunctionReturn(PETSC_SUCCESS);
199: }

201: /*@C
202:   DMTSCopy - copies the information in a `DMTS` to another `DMTS`

204:   Not Collective

206:   Input Parameters:
207: + kdm  - Original `DMTS`
208: - nkdm - `DMTS` to receive the data, should have been created with `DMTSCreate()`

210:   Level: developer

212: .seealso: [](ch_ts), `DMTSCreate()`, `DMTSDestroy()`
213: @*/
214: PetscErrorCode DMTSCopy(DMTS kdm, DMTS nkdm)
215: {
216:   PetscFunctionBegin;
219:   nkdm->ops->rhsfunction = kdm->ops->rhsfunction;
220:   nkdm->ops->rhsjacobian = kdm->ops->rhsjacobian;
221:   nkdm->ops->ifunction   = kdm->ops->ifunction;
222:   nkdm->ops->ijacobian   = kdm->ops->ijacobian;
223:   nkdm->ops->i2function  = kdm->ops->i2function;
224:   nkdm->ops->i2jacobian  = kdm->ops->i2jacobian;
225:   nkdm->ops->solution    = kdm->ops->solution;
226:   nkdm->ops->destroy     = kdm->ops->destroy;
227:   nkdm->ops->duplicate   = kdm->ops->duplicate;

229:   nkdm->solutionctx             = kdm->solutionctx;
230:   nkdm->rhsfunctionctxcontainer = kdm->rhsfunctionctxcontainer;
231:   nkdm->rhsjacobianctxcontainer = kdm->rhsjacobianctxcontainer;
232:   nkdm->ifunctionctxcontainer   = kdm->ifunctionctxcontainer;
233:   nkdm->ijacobianctxcontainer   = kdm->ijacobianctxcontainer;
234:   nkdm->i2functionctxcontainer  = kdm->i2functionctxcontainer;
235:   nkdm->i2jacobianctxcontainer  = kdm->i2jacobianctxcontainer;
236:   if (nkdm->rhsfunctionctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "rhs function ctx", (PetscObject)nkdm->rhsfunctionctxcontainer));
237:   if (nkdm->rhsjacobianctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "rhs jacobian ctx", (PetscObject)nkdm->rhsjacobianctxcontainer));
238:   if (nkdm->ifunctionctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "ifunction ctx", (PetscObject)nkdm->ifunctionctxcontainer));
239:   if (nkdm->ijacobianctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "ijacobian ctx", (PetscObject)nkdm->ijacobianctxcontainer));
240:   if (nkdm->i2functionctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "i2function ctx", (PetscObject)nkdm->i2functionctxcontainer));
241:   if (nkdm->i2jacobianctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "i2jacobian ctx", (PetscObject)nkdm->i2jacobianctxcontainer));

243:   nkdm->data = kdm->data;

245:   /*
246:   nkdm->fortran_func_pointers[0] = kdm->fortran_func_pointers[0];
247:   nkdm->fortran_func_pointers[1] = kdm->fortran_func_pointers[1];
248:   nkdm->fortran_func_pointers[2] = kdm->fortran_func_pointers[2];
249:   */

251:   /* implementation specific copy hooks */
252:   PetscTryTypeMethod(kdm, duplicate, nkdm);
253:   PetscFunctionReturn(PETSC_SUCCESS);
254: }

256: /*@C
257:   DMGetDMTS - get read-only private `DMTS` context from a `DM`

259:   Not Collective

261:   Input Parameter:
262: . dm - `DM` to be used with `TS`

264:   Output Parameter:
265: . tsdm - private `DMTS` context

267:   Level: developer

269:   Notes:
270:   Use `DMGetDMTSWrite()` if write access is needed. The `DMTSSetXXX()` API should be used wherever possible.

272: .seealso: [](ch_ts), `DMTS`, `DMGetDMTSWrite()`
273: @*/
274: PetscErrorCode DMGetDMTS(DM dm, DMTS *tsdm)
275: {
276:   PetscFunctionBegin;
278:   *tsdm = (DMTS)dm->dmts;
279:   if (!*tsdm) {
280:     PetscCall(PetscInfo(dm, "Creating new DMTS\n"));
281:     PetscCall(DMTSCreate(PetscObjectComm((PetscObject)dm), tsdm));
282:     dm->dmts            = (PetscObject)*tsdm;
283:     (*tsdm)->originaldm = dm;
284:     PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_DMTS, DMRestrictHook_DMTS, NULL));
285:     PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_DMTS, DMSubDomainRestrictHook_DMTS, NULL));
286:   }
287:   PetscFunctionReturn(PETSC_SUCCESS);
288: }

290: /*@C
291:   DMGetDMTSWrite - get write access to private `DMTS` context from a `DM`

293:   Not Collective

295:   Input Parameter:
296: . dm - `DM` to be used with `TS`

298:   Output Parameter:
299: . tsdm - private `DMTS` context

301:   Level: developer

303: .seealso: [](ch_ts), `DMTS`, `DMGetDMTS()`
304: @*/
305: PetscErrorCode DMGetDMTSWrite(DM dm, DMTS *tsdm)
306: {
307:   DMTS sdm;

309:   PetscFunctionBegin;
311:   PetscCall(DMGetDMTS(dm, &sdm));
312:   PetscCheck(sdm->originaldm, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DMTS has a NULL originaldm");
313:   if (sdm->originaldm != dm) { /* Copy on write */
314:     DMTS oldsdm = sdm;
315:     PetscCall(PetscInfo(dm, "Copying DMTS due to write\n"));
316:     PetscCall(DMTSCreate(PetscObjectComm((PetscObject)dm), &sdm));
317:     PetscCall(DMTSCopy(oldsdm, sdm));
318:     PetscCall(DMTSDestroy((DMTS *)&dm->dmts));
319:     dm->dmts        = (PetscObject)sdm;
320:     sdm->originaldm = dm;
321:   }
322:   *tsdm = sdm;
323:   PetscFunctionReturn(PETSC_SUCCESS);
324: }

326: /*@C
327:   DMCopyDMTS - copies a `DMTS` context to a new `DM`

329:   Logically Collective

331:   Input Parameters:
332: + dmsrc  - `DM` to obtain context from
333: - dmdest - `DM` to add context to

335:   Level: developer

337:   Note:
338:   The context is copied by reference. This function does not ensure that a context exists.

340: .seealso: [](ch_ts), `DMTS`, `DMGetDMTS()`, `TSSetDM()`
341: @*/
342: PetscErrorCode DMCopyDMTS(DM dmsrc, DM dmdest)
343: {
344:   PetscFunctionBegin;
347:   PetscCall(DMTSDestroy((DMTS *)&dmdest->dmts));
348:   dmdest->dmts = dmsrc->dmts;
349:   PetscCall(PetscObjectReference(dmdest->dmts));
350:   PetscCall(DMCoarsenHookAdd(dmdest, DMCoarsenHook_DMTS, DMRestrictHook_DMTS, NULL));
351:   PetscCall(DMSubDomainHookAdd(dmdest, DMSubDomainHook_DMTS, DMSubDomainRestrictHook_DMTS, NULL));
352:   PetscFunctionReturn(PETSC_SUCCESS);
353: }

355: /*@C
356:   DMTSSetIFunction - set `TS` implicit function evaluation function into a `DMTS`

358:   Not Collective

360:   Input Parameters:
361: + dm   - `DM` to be used with `TS`
362: . func - function evaluating f(t,u,u_t)
363: - ctx  - context for residual evaluation

365:   Level: developer

367:   Note:
368:   `TSSetIFunction()` is normally used, but it calls this function internally because the user context is actually
369:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
370:   not. If `DM` took a more central role at some later date, this could become the primary method of setting the residual.

372: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSIFunctionFn`
373: @*/
374: PetscErrorCode DMTSSetIFunction(DM dm, TSIFunctionFn *func, void *ctx)
375: {
376:   DMTS tsdm;

378:   PetscFunctionBegin;
380:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
381:   if (func) tsdm->ops->ifunction = func;
382:   if (ctx) {
383:     PetscContainer ctxcontainer;
384:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
385:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
386:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "ifunction ctx", (PetscObject)ctxcontainer));
387:     tsdm->ifunctionctxcontainer = ctxcontainer;
388:     PetscCall(PetscContainerDestroy(&ctxcontainer));
389:   }
390:   PetscFunctionReturn(PETSC_SUCCESS);
391: }

393: /*@C
394:   DMTSSetIFunctionContextDestroy - set `TS` implicit evaluation context destroy function into a `DMTS`

396:   Not Collective

398:   Input Parameters:
399: + dm - `DM` to be used with `TS`
400: - f  - implicit evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence

402:   Level: developer

404: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetIFunction()`, `TSSetIFunction()`, `PetscCtxDestroyFn`
405: @*/
406: PetscErrorCode DMTSSetIFunctionContextDestroy(DM dm, PetscCtxDestroyFn *f)
407: {
408:   DMTS tsdm;

410:   PetscFunctionBegin;
412:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
413:   if (tsdm->ifunctionctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->ifunctionctxcontainer, f));
414:   PetscFunctionReturn(PETSC_SUCCESS);
415: }

417: PetscErrorCode DMTSUnsetIFunctionContext_Internal(DM dm)
418: {
419:   DMTS tsdm;

421:   PetscFunctionBegin;
423:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
424:   PetscCall(DMTSUnsetIFunctionContext_DMTS(tsdm));
425:   PetscFunctionReturn(PETSC_SUCCESS);
426: }

428: /*@C
429:   DMTSGetIFunction - get `TS` implicit residual evaluation function from a `DMTS`

431:   Not Collective

433:   Input Parameter:
434: . dm - `DM` to be used with `TS`

436:   Output Parameters:
437: + func - function evaluation function, for calling sequence see `TSIFunctionFn`
438: - ctx  - context for residual evaluation

440:   Level: developer

442:   Note:
443:   `TSGetIFunction()` is normally used, but it calls this function internally because the user context is actually
444:   associated with the `DM`.

446: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `DMTSSetIFunction()`, `TSIFunctionFn`
447: @*/
448: PetscErrorCode DMTSGetIFunction(DM dm, TSIFunctionFn **func, void **ctx)
449: {
450:   DMTS tsdm;

452:   PetscFunctionBegin;
454:   PetscCall(DMGetDMTS(dm, &tsdm));
455:   if (func) *func = tsdm->ops->ifunction;
456:   if (ctx) {
457:     if (tsdm->ifunctionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->ifunctionctxcontainer, ctx));
458:     else *ctx = NULL;
459:   }
460:   PetscFunctionReturn(PETSC_SUCCESS);
461: }

463: /*@C
464:   DMTSSetI2Function - set `TS` implicit function evaluation function for 2nd order systems into a `TSDM`

466:   Not Collective

468:   Input Parameters:
469: + dm  - `DM` to be used with `TS`
470: . fun - function evaluation routine
471: - ctx - context for residual evaluation

473:   Level: developer

475:   Note:
476:   `TSSetI2Function()` is normally used, but it calls this function internally because the user context is actually
477:   associated with the `DM`.

479: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSSetI2Function()`
480: @*/
481: PetscErrorCode DMTSSetI2Function(DM dm, TSI2FunctionFn *fun, void *ctx)
482: {
483:   DMTS tsdm;

485:   PetscFunctionBegin;
487:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
488:   if (fun) tsdm->ops->i2function = fun;
489:   if (ctx) {
490:     PetscContainer ctxcontainer;
491:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
492:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
493:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "i2function ctx", (PetscObject)ctxcontainer));
494:     tsdm->i2functionctxcontainer = ctxcontainer;
495:     PetscCall(PetscContainerDestroy(&ctxcontainer));
496:   }
497:   PetscFunctionReturn(PETSC_SUCCESS);
498: }

500: /*@C
501:   DMTSSetI2FunctionContextDestroy - set `TS` implicit evaluation for 2nd order systems context destroy into a `DMTS`

503:   Not Collective

505:   Input Parameters:
506: + dm - `DM` to be used with `TS`
507: - f  - implicit evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence

509:   Level: developer

511:   Note:
512:   `TSSetI2FunctionContextDestroy()` is normally used, but it calls this function internally because the user context is actually
513:   associated with the `DM`.

515: .seealso: [](ch_ts), `DMTS`, `TSSetI2FunctionContextDestroy()`, `DMTSSetI2Function()`, `TSSetI2Function()`
516: @*/
517: PetscErrorCode DMTSSetI2FunctionContextDestroy(DM dm, PetscCtxDestroyFn *f)
518: {
519:   DMTS tsdm;

521:   PetscFunctionBegin;
523:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
524:   if (tsdm->i2functionctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->i2functionctxcontainer, f));
525:   PetscFunctionReturn(PETSC_SUCCESS);
526: }

528: PetscErrorCode DMTSUnsetI2FunctionContext_Internal(DM dm)
529: {
530:   DMTS tsdm;

532:   PetscFunctionBegin;
534:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
535:   PetscCall(DMTSUnsetI2FunctionContext_DMTS(tsdm));
536:   PetscFunctionReturn(PETSC_SUCCESS);
537: }

539: /*@C
540:   DMTSGetI2Function - get `TS` implicit residual evaluation function for 2nd order systems from a `DMTS`

542:   Not Collective

544:   Input Parameter:
545: . dm - `DM` to be used with `TS`

547:   Output Parameters:
548: + fun - function evaluation function, for calling sequence see `TSSetI2Function()`
549: - ctx - context for residual evaluation

551:   Level: developer

553:   Note:
554:   `TSGetI2Function()` is normally used, but it calls this function internally because the user context is actually
555:   associated with the `DM`.

557: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetI2Function()`, `TSGetI2Function()`
558: @*/
559: PetscErrorCode DMTSGetI2Function(DM dm, TSI2FunctionFn **fun, void **ctx)
560: {
561:   DMTS tsdm;

563:   PetscFunctionBegin;
565:   PetscCall(DMGetDMTS(dm, &tsdm));
566:   if (fun) *fun = tsdm->ops->i2function;
567:   if (ctx) {
568:     if (tsdm->i2functionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->i2functionctxcontainer, ctx));
569:     else *ctx = NULL;
570:   }
571:   PetscFunctionReturn(PETSC_SUCCESS);
572: }

574: /*@C
575:   DMTSSetI2Jacobian - set `TS` implicit Jacobian evaluation function for 2nd order systems from a `DMTS`

577:   Not Collective

579:   Input Parameters:
580: + dm  - `DM` to be used with `TS`
581: . jac - Jacobian evaluation routine
582: - ctx - context for Jacobian evaluation

584:   Level: developer

586:   Note:
587:   `TSSetI2Jacobian()` is normally used, but it calls this function internally because the user context is actually
588:   associated with the `DM`.

590: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSI2JacobianFn`, `TSSetI2Jacobian()`
591: @*/
592: PetscErrorCode DMTSSetI2Jacobian(DM dm, TSI2JacobianFn *jac, void *ctx)
593: {
594:   DMTS tsdm;

596:   PetscFunctionBegin;
598:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
599:   if (jac) tsdm->ops->i2jacobian = jac;
600:   if (ctx) {
601:     PetscContainer ctxcontainer;
602:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
603:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
604:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "i2jacobian ctx", (PetscObject)ctxcontainer));
605:     tsdm->i2jacobianctxcontainer = ctxcontainer;
606:     PetscCall(PetscContainerDestroy(&ctxcontainer));
607:   }
608:   PetscFunctionReturn(PETSC_SUCCESS);
609: }

611: /*@C
612:   DMTSSetI2JacobianContextDestroy - set `TS` implicit Jacobian evaluation for 2nd order systems context destroy function into a `DMTS`

614:   Not Collective

616:   Input Parameters:
617: + dm - `DM` to be used with `TS`
618: - f  - implicit Jacobian evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence

620:   Level: developer

622:   Note:
623:   Normally `TSSetI2JacobianContextDestroy()` is used

625: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSSetI2JacobianContextDestroy()`, `DMTSSetI2Jacobian()`, `TSSetI2Jacobian()`
626: @*/
627: PetscErrorCode DMTSSetI2JacobianContextDestroy(DM dm, PetscCtxDestroyFn *f)
628: {
629:   DMTS tsdm;

631:   PetscFunctionBegin;
633:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
634:   if (tsdm->i2jacobianctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->i2jacobianctxcontainer, f));
635:   PetscFunctionReturn(PETSC_SUCCESS);
636: }

638: PetscErrorCode DMTSUnsetI2JacobianContext_Internal(DM dm)
639: {
640:   DMTS tsdm;

642:   PetscFunctionBegin;
644:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
645:   PetscCall(DMTSUnsetI2JacobianContext_DMTS(tsdm));
646:   PetscFunctionReturn(PETSC_SUCCESS);
647: }

649: /*@C
650:   DMTSGetI2Jacobian - get `TS` implicit Jacobian evaluation function for 2nd order systems from a `DMTS`

652:   Not Collective

654:   Input Parameter:
655: . dm - `DM` to be used with `TS`

657:   Output Parameters:
658: + jac - Jacobian evaluation function,  for calling sequence see `TSI2JacobianFn`
659: - ctx - context for Jacobian evaluation

661:   Level: developer

663:   Note:
664:   `TSGetI2Jacobian()` is normally used, but it calls this function internally because the user context is actually
665:   associated with the `DM`.

667: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetI2Jacobian()`, `TSGetI2Jacobian()`, `TSI2JacobianFn`
668: @*/
669: PetscErrorCode DMTSGetI2Jacobian(DM dm, TSI2JacobianFn **jac, void **ctx)
670: {
671:   DMTS tsdm;

673:   PetscFunctionBegin;
675:   PetscCall(DMGetDMTS(dm, &tsdm));
676:   if (jac) *jac = tsdm->ops->i2jacobian;
677:   if (ctx) {
678:     if (tsdm->i2jacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->i2jacobianctxcontainer, ctx));
679:     else *ctx = NULL;
680:   }
681:   PetscFunctionReturn(PETSC_SUCCESS);
682: }

684: /*@C
685:   DMTSSetRHSFunction - set `TS` explicit residual evaluation function into a `DMTS`

687:   Not Collective

689:   Input Parameters:
690: + dm   - `DM` to be used with `TS`
691: . func - RHS function evaluation routine, see `TSRHSFunctionFn` for the calling sequence
692: - ctx  - context for residual evaluation

694:   Level: developer

696:   Note:
697:   `TSSetRHSFunction()` is normally used, but it calls this function internally because the user context is actually
698:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
699:   not. If `DM` took a more central role at some later date, this could become the primary method of setting the residual.

701: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSRHSFunctionFn`
702: @*/
703: PetscErrorCode DMTSSetRHSFunction(DM dm, TSRHSFunctionFn *func, void *ctx)
704: {
705:   DMTS tsdm;

707:   PetscFunctionBegin;
709:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
710:   if (func) tsdm->ops->rhsfunction = func;
711:   if (ctx) {
712:     PetscContainer ctxcontainer;
713:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
714:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
715:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "rhs function ctx", (PetscObject)ctxcontainer));
716:     tsdm->rhsfunctionctxcontainer = ctxcontainer;
717:     PetscCall(PetscContainerDestroy(&ctxcontainer));
718:   }
719:   PetscFunctionReturn(PETSC_SUCCESS);
720: }

722: /*@C
723:   DMTSSetRHSFunctionContextDestroy - set `TS` explicit residual evaluation context destroy function into a `DMTS`

725:   Not Collective

727:   Input Parameters:
728: + dm - `DM` to be used with `TS`
729: - f  - explicit evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence

731:   Level: developer

733:   Note:
734:   `TSSetRHSFunctionContextDestroy()` is normally used, but it calls this function internally because the user context is actually
735:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
736:   not.

738:   Developer Notes:
739:   If `DM` took a more central role at some later date, this could become the primary method of setting the residual.

741: .seealso: [](ch_ts), `DMTS`, `TSSetRHSFunctionContextDestroy()`, `DMTSSetRHSFunction()`, `TSSetRHSFunction()`
742: @*/
743: PetscErrorCode DMTSSetRHSFunctionContextDestroy(DM dm, PetscCtxDestroyFn *f)
744: {
745:   DMTS tsdm;

747:   PetscFunctionBegin;
749:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
750:   if (tsdm->rhsfunctionctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->rhsfunctionctxcontainer, f));
751:   PetscFunctionReturn(PETSC_SUCCESS);
752: }

754: PetscErrorCode DMTSUnsetRHSFunctionContext_Internal(DM dm)
755: {
756:   DMTS tsdm;

758:   PetscFunctionBegin;
760:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
761:   PetscCall(DMTSUnsetRHSFunctionContext_DMTS(tsdm));
762:   tsdm->rhsfunctionctxcontainer = NULL;
763:   PetscFunctionReturn(PETSC_SUCCESS);
764: }

766: /*@C
767:   DMTSSetTransientVariable - sets function to transform from state to transient variables into a `DMTS`

769:   Logically Collective

771:   Input Parameters:
772: + dm   - `DM` to be used with `TS`
773: . tvar - a function that transforms to transient variables, see `TSTransientVariableFn` for the calling sequence
774: - ctx  - a context for tvar

776:   Level: developer

778:   Notes:
779:   Normally `TSSetTransientVariable()` is used

781:   This is typically used to transform from primitive to conservative variables so that a time integrator (e.g., `TSBDF`)
782:   can be conservative.  In this context, primitive variables P are used to model the state (e.g., because they lead to
783:   well-conditioned formulations even in limiting cases such as low-Mach or zero porosity).  The transient variable is
784:   C(P), specified by calling this function.  An IFunction thus receives arguments (P, Cdot) and the IJacobian must be
785:   evaluated via the chain rule, as in

787:   $$
788:   dF/dP + shift * dF/dCdot dC/dP.
789:   $$

791: .seealso: [](ch_ts), `DMTS`, `TS`, `TSBDF`, `TSSetTransientVariable()`, `DMTSGetTransientVariable()`, `DMTSSetIFunction()`, `DMTSSetIJacobian()`, `TSTransientVariableFn`
792: @*/
793: PetscErrorCode DMTSSetTransientVariable(DM dm, TSTransientVariableFn *tvar, void *ctx)
794: {
795:   DMTS dmts;

797:   PetscFunctionBegin;
799:   PetscCall(DMGetDMTSWrite(dm, &dmts));
800:   dmts->ops->transientvar = tvar;
801:   dmts->transientvarctx   = ctx;
802:   PetscFunctionReturn(PETSC_SUCCESS);
803: }

805: /*@C
806:   DMTSGetTransientVariable - gets function to transform from state to transient variables set with `DMTSSetTransientVariable()` from a `TSDM`

808:   Logically Collective

810:   Input Parameter:
811: . dm - `DM` to be used with `TS`

813:   Output Parameters:
814: + tvar - a function that transforms to transient variables, see `TSTransientVariableFn` for the calling sequence
815: - ctx  - a context for tvar

817:   Level: developer

819:   Note:
820:   Normally `TSSetTransientVariable()` is used

822: .seealso: [](ch_ts), `DMTS`, `DM`, `DMTSSetTransientVariable()`, `DMTSGetIFunction()`, `DMTSGetIJacobian()`, `TSTransientVariableFn`
823: @*/
824: PetscErrorCode DMTSGetTransientVariable(DM dm, TSTransientVariableFn **tvar, void *ctx)
825: {
826:   DMTS dmts;

828:   PetscFunctionBegin;
830:   PetscCall(DMGetDMTS(dm, &dmts));
831:   if (tvar) *tvar = dmts->ops->transientvar;
832:   if (ctx) *(void **)ctx = dmts->transientvarctx;
833:   PetscFunctionReturn(PETSC_SUCCESS);
834: }

836: /*@C
837:   DMTSGetSolutionFunction - gets the `TS` solution evaluation function from a `DMTS`

839:   Not Collective

841:   Input Parameter:
842: . dm - `DM` to be used with `TS`

844:   Output Parameters:
845: + func - solution function evaluation function, for calling sequence see `TSSolutionFn`
846: - ctx  - context for solution evaluation

848:   Level: developer

850: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `DMTSSetSolutionFunction()`, `TSSolutionFn`
851: @*/
852: PetscErrorCode DMTSGetSolutionFunction(DM dm, TSSolutionFn **func, void **ctx)
853: {
854:   DMTS tsdm;

856:   PetscFunctionBegin;
858:   PetscCall(DMGetDMTS(dm, &tsdm));
859:   if (func) *func = tsdm->ops->solution;
860:   if (ctx) *ctx = tsdm->solutionctx;
861:   PetscFunctionReturn(PETSC_SUCCESS);
862: }

864: /*@C
865:   DMTSSetSolutionFunction - set `TS` solution evaluation function into a `DMTS`

867:   Not Collective

869:   Input Parameters:
870: + dm   - `DM` to be used with `TS`
871: . func - solution function evaluation routine, for calling sequence see `TSSolutionFn`
872: - ctx  - context for solution evaluation

874:   Level: developer

876:   Note:
877:   `TSSetSolutionFunction()` is normally used, but it calls this function internally because the user context is actually
878:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
879:   not. If `DM` took a more central role at some later date, this could become the primary method of setting the residual.

881: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSGetSolutionFunction()`, `TSSolutionFn`
882: @*/
883: PetscErrorCode DMTSSetSolutionFunction(DM dm, TSSolutionFn *func, void *ctx)
884: {
885:   DMTS tsdm;

887:   PetscFunctionBegin;
889:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
890:   if (func) tsdm->ops->solution = func;
891:   if (ctx) tsdm->solutionctx = ctx;
892:   PetscFunctionReturn(PETSC_SUCCESS);
893: }

895: /*@C
896:   DMTSSetForcingFunction - set `TS` forcing function evaluation function into a `DMTS`

898:   Not Collective

900:   Input Parameters:
901: + dm   - `DM` to be used with `TS`
902: . func - forcing function evaluation routine, for calling sequence see `TSForcingFn`
903: - ctx  - context for solution evaluation

905:   Level: developer

907:   Note:
908:   `TSSetForcingFunction()` is normally used, but it calls this function internally because the user context is actually
909:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
910:   not. If `DM` took a more central role at some later date, this could become the primary method of setting the residual.

912: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSForcingFn`, `TSSetForcingFunction()`, `DMTSGetForcingFunction()`
913: @*/
914: PetscErrorCode DMTSSetForcingFunction(DM dm, TSForcingFn *func, void *ctx)
915: {
916:   DMTS tsdm;

918:   PetscFunctionBegin;
920:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
921:   if (func) tsdm->ops->forcing = func;
922:   if (ctx) tsdm->forcingctx = ctx;
923:   PetscFunctionReturn(PETSC_SUCCESS);
924: }

926: /*@C
927:   DMTSGetForcingFunction - get `TS` forcing function evaluation function from a `DMTS`

929:   Not Collective

931:   Input Parameter:
932: . dm - `DM` to be used with `TS`

934:   Output Parameters:
935: + f   - forcing function evaluation function; see `TSForcingFn` for the calling sequence
936: - ctx - context for solution evaluation

938:   Level: developer

940:   Note:
941:   `TSSetForcingFunction()` is normally used, but it calls this function internally because the user context is actually
942:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
943:   not. If `DM` took a more central role at some later date, this could become the primary method of setting the residual.

945: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSSetForcingFunction()`, `TSForcingFn`
946: @*/
947: PetscErrorCode DMTSGetForcingFunction(DM dm, TSForcingFn **f, void **ctx)
948: {
949:   DMTS tsdm;

951:   PetscFunctionBegin;
953:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
954:   if (f) *f = tsdm->ops->forcing;
955:   if (ctx) *ctx = tsdm->forcingctx;
956:   PetscFunctionReturn(PETSC_SUCCESS);
957: }

959: /*@C
960:   DMTSGetRHSFunction - get `TS` explicit residual evaluation function from a `DMTS`

962:   Not Collective

964:   Input Parameter:
965: . dm - `DM` to be used with `TS`

967:   Output Parameters:
968: + func - residual evaluation function, for calling sequence see `TSRHSFunctionFn`
969: - ctx  - context for residual evaluation

971:   Level: developer

973:   Note:
974:   `TSGetRHSFunction()` is normally used, but it calls this function internally because the user context is actually
975:   associated with the DM.

977: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSRHSFunctionFn`, `TSGetRHSFunction()`
978: @*/
979: PetscErrorCode DMTSGetRHSFunction(DM dm, TSRHSFunctionFn **func, void **ctx)
980: {
981:   DMTS tsdm;

983:   PetscFunctionBegin;
985:   PetscCall(DMGetDMTS(dm, &tsdm));
986:   if (func) *func = tsdm->ops->rhsfunction;
987:   if (ctx) {
988:     if (tsdm->rhsfunctionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->rhsfunctionctxcontainer, ctx));
989:     else *ctx = NULL;
990:   }
991:   PetscFunctionReturn(PETSC_SUCCESS);
992: }

994: /*@C
995:   DMTSSetIJacobian - set `TS` Jacobian evaluation function into a `DMTS`

997:   Not Collective

999:   Input Parameters:
1000: + dm   - `DM` to be used with `TS`
1001: . func - Jacobian evaluation routine, see `TSIJacobianFn` for the calling sequence
1002: - ctx  - context for residual evaluation

1004:   Level: developer

1006:   Note:
1007:   `TSSetIJacobian()` is normally used, but it calls this function internally because the user context is actually
1008:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
1009:   not. If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian.

1011: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSIJacobianFn`, `DMTSGetIJacobian()`, `TSSetIJacobian()`
1012: @*/
1013: PetscErrorCode DMTSSetIJacobian(DM dm, TSIJacobianFn *func, void *ctx)
1014: {
1015:   DMTS tsdm;

1017:   PetscFunctionBegin;
1019:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1020:   if (func) tsdm->ops->ijacobian = func;
1021:   if (ctx) {
1022:     PetscContainer ctxcontainer;
1023:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
1024:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1025:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "ijacobian ctx", (PetscObject)ctxcontainer));
1026:     tsdm->ijacobianctxcontainer = ctxcontainer;
1027:     PetscCall(PetscContainerDestroy(&ctxcontainer));
1028:   }
1029:   PetscFunctionReturn(PETSC_SUCCESS);
1030: }

1032: /*@C
1033:   DMTSSetIJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function into a `DMTS`

1035:   Not Collective

1037:   Input Parameters:
1038: + dm - `DM` to be used with `TS`
1039: - f  - Jacobian evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence

1041:   Level: developer

1043:   Note:
1044:   `TSSetIJacobianContextDestroy()` is normally used, but it calls this function internally because the user context is actually
1045:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
1046:   not.

1048:   Developer Notes:
1049:   If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian.

1051: .seealso: [](ch_ts), `DMTS`, `TSSetIJacobianContextDestroy()`, `TSSetI2JacobianContextDestroy()`, `DMTSSetIJacobian()`, `TSSetIJacobian()`
1052: @*/
1053: PetscErrorCode DMTSSetIJacobianContextDestroy(DM dm, PetscCtxDestroyFn *f)
1054: {
1055:   DMTS tsdm;

1057:   PetscFunctionBegin;
1059:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1060:   if (tsdm->ijacobianctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->ijacobianctxcontainer, f));
1061:   PetscFunctionReturn(PETSC_SUCCESS);
1062: }

1064: PetscErrorCode DMTSUnsetIJacobianContext_Internal(DM dm)
1065: {
1066:   DMTS tsdm;

1068:   PetscFunctionBegin;
1070:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1071:   PetscCall(DMTSUnsetIJacobianContext_DMTS(tsdm));
1072:   PetscFunctionReturn(PETSC_SUCCESS);
1073: }

1075: /*@C
1076:   DMTSGetIJacobian - get `TS` Jacobian evaluation function from a `DMTS`

1078:   Not Collective

1080:   Input Parameter:
1081: . dm - `DM` to be used with `TS`

1083:   Output Parameters:
1084: + func - Jacobian evaluation function, for calling sequence see `TSIJacobianFn`
1085: - ctx  - context for residual evaluation

1087:   Level: developer

1089:   Note:
1090:   `TSGetIJacobian()` is normally used, but it calls this function internally because the user context is actually
1091:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
1092:   not. If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian.

1094: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetIJacobian()`, `TSIJacobianFn`
1095: @*/
1096: PetscErrorCode DMTSGetIJacobian(DM dm, TSIJacobianFn **func, void **ctx)
1097: {
1098:   DMTS tsdm;

1100:   PetscFunctionBegin;
1102:   PetscCall(DMGetDMTS(dm, &tsdm));
1103:   if (func) *func = tsdm->ops->ijacobian;
1104:   if (ctx) {
1105:     if (tsdm->ijacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->ijacobianctxcontainer, ctx));
1106:     else *ctx = NULL;
1107:   }
1108:   PetscFunctionReturn(PETSC_SUCCESS);
1109: }

1111: /*@C
1112:   DMTSSetRHSJacobian - set `TS` Jacobian evaluation function into a `DMTS`

1114:   Not Collective

1116:   Input Parameters:
1117: + dm   - `DM` to be used with `TS`
1118: . func - Jacobian evaluation routine, for calling sequence see `TSIJacobianFn`
1119: - ctx  - context for residual evaluation

1121:   Level: developer

1123:   Note:
1124:   `TSSetRHSJacobian()` is normally used, but it calls this function internally because the user context is actually
1125:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
1126:   not.

1128:   Developer Notes:
1129:   If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian.

1131: .seealso: [](ch_ts), `DMTS`, `TSRHSJacobianFn`, `DMTSGetRHSJacobian()`, `TSSetRHSJacobian()`
1132: @*/
1133: PetscErrorCode DMTSSetRHSJacobian(DM dm, TSRHSJacobianFn *func, void *ctx)
1134: {
1135:   DMTS tsdm;

1137:   PetscFunctionBegin;
1139:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1140:   if (func) tsdm->ops->rhsjacobian = func;
1141:   if (ctx) {
1142:     PetscContainer ctxcontainer;
1143:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
1144:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1145:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "rhs jacobian ctx", (PetscObject)ctxcontainer));
1146:     tsdm->rhsjacobianctxcontainer = ctxcontainer;
1147:     PetscCall(PetscContainerDestroy(&ctxcontainer));
1148:   }
1149:   PetscFunctionReturn(PETSC_SUCCESS);
1150: }

1152: /*@C
1153:   DMTSSetRHSJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function from a `DMTS`

1155:   Not Collective

1157:   Input Parameters:
1158: + dm - `DM` to be used with `TS`
1159: - f  - Jacobian evaluation context destroy function, see `PetscCtxDestroyFn` for its calling sequence

1161:   Level: developer

1163:   Note:
1164:   The user usually calls `TSSetRHSJacobianContextDestroy()` which calls this routine

1166: .seealso: [](ch_ts), `DMTS`, `TS`, `TSSetRHSJacobianContextDestroy()`, `DMTSSetRHSJacobian()`, `TSSetRHSJacobian()`
1167: @*/
1168: PetscErrorCode DMTSSetRHSJacobianContextDestroy(DM dm, PetscCtxDestroyFn *f)
1169: {
1170:   DMTS tsdm;

1172:   PetscFunctionBegin;
1174:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1175:   if (tsdm->rhsjacobianctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->rhsjacobianctxcontainer, f));
1176:   PetscFunctionReturn(PETSC_SUCCESS);
1177: }

1179: PetscErrorCode DMTSUnsetRHSJacobianContext_Internal(DM dm)
1180: {
1181:   DMTS tsdm;

1183:   PetscFunctionBegin;
1185:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1186:   PetscCall(DMTSUnsetRHSJacobianContext_DMTS(tsdm));
1187:   PetscFunctionReturn(PETSC_SUCCESS);
1188: }

1190: /*@C
1191:   DMTSGetRHSJacobian - get `TS` Jacobian evaluation function from a `DMTS`

1193:   Not Collective

1195:   Input Parameter:
1196: . dm - `DM` to be used with `TS`

1198:   Output Parameters:
1199: + func - Jacobian evaluation function, for calling sequence see `TSRHSJacobianFn`
1200: - ctx  - context for residual evaluation

1202:   Level: developer

1204:   Note:
1205:   `TSGetRHSJacobian()` is normally used, but it calls this function internally because the user context is actually
1206:   associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
1207:   not. If `DM` took a more central role at some later date, this could become the primary method of setting the Jacobian.

1209: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetRHSJacobian()`, `TSRHSJacobianFn`
1210: @*/
1211: PetscErrorCode DMTSGetRHSJacobian(DM dm, TSRHSJacobianFn **func, void **ctx)
1212: {
1213:   DMTS tsdm;

1215:   PetscFunctionBegin;
1217:   PetscCall(DMGetDMTS(dm, &tsdm));
1218:   if (func) *func = tsdm->ops->rhsjacobian;
1219:   if (ctx) {
1220:     if (tsdm->rhsjacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->rhsjacobianctxcontainer, ctx));
1221:     else *ctx = NULL;
1222:   }
1223:   PetscFunctionReturn(PETSC_SUCCESS);
1224: }

1226: /*@C
1227:   DMTSSetIFunctionSerialize - sets functions used to view and load a `TSIFunctionFn` context

1229:   Not Collective

1231:   Input Parameters:
1232: + dm   - `DM` to be used with `TS`
1233: . view - viewer function
1234: - load - loading function

1236:   Level: developer

1238: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`
1239: @*/
1240: PetscErrorCode DMTSSetIFunctionSerialize(DM dm, PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*load)(void **, PetscViewer))
1241: {
1242:   DMTS tsdm;

1244:   PetscFunctionBegin;
1246:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1247:   tsdm->ops->ifunctionview = view;
1248:   tsdm->ops->ifunctionload = load;
1249:   PetscFunctionReturn(PETSC_SUCCESS);
1250: }

1252: /*@C
1253:   DMTSSetIJacobianSerialize - sets functions used to view and load a `TSIJacobianFn` context

1255:   Not Collective

1257:   Input Parameters:
1258: + dm   - `DM` to be used with `TS`
1259: . view - viewer function
1260: - load - loading function

1262:   Level: developer

1264: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`
1265: @*/
1266: PetscErrorCode DMTSSetIJacobianSerialize(DM dm, PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*load)(void **, PetscViewer))
1267: {
1268:   DMTS tsdm;

1270:   PetscFunctionBegin;
1272:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1273:   tsdm->ops->ijacobianview = view;
1274:   tsdm->ops->ijacobianload = load;
1275:   PetscFunctionReturn(PETSC_SUCCESS);
1276: }