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:     PetscCtx 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:     PetscCtx 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 isbinary;

100:   PetscFunctionBegin;
101:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
102:   if (isbinary) {
103:     struct {
104:       TSIFunctionFn *ifunction;
105:     } funcstruct;
106:     struct {
107:       PetscErrorCode (*ifunctionview)(void *, PetscViewer);
108:     } funcviewstruct;
109:     struct {
110:       PetscErrorCode (*ifunctionload)(void **, PetscViewer);
111:     } funcloadstruct;
112:     struct {
113:       TSIJacobianFn *ijacobian;
114:     } jacstruct;
115:     struct {
116:       PetscErrorCode (*ijacobianview)(void *, PetscViewer);
117:     } jacviewstruct;
118:     struct {
119:       PetscErrorCode (*ijacobianload)(void **, PetscViewer);
120:     } jacloadstruct;

122:     funcstruct.ifunction         = kdm->ops->ifunction;
123:     funcviewstruct.ifunctionview = kdm->ops->ifunctionview;
124:     funcloadstruct.ifunctionload = kdm->ops->ifunctionload;
125:     PetscCall(PetscViewerBinaryWrite(viewer, &funcstruct, 1, PETSC_FUNCTION));
126:     PetscCall(PetscViewerBinaryWrite(viewer, &funcviewstruct, 1, PETSC_FUNCTION));
127:     PetscCall(PetscViewerBinaryWrite(viewer, &funcloadstruct, 1, PETSC_FUNCTION));
128:     if (kdm->ops->ifunctionview) {
129:       PetscCtx ctx;

131:       PetscCall(PetscContainerGetPointer(kdm->ifunctionctxcontainer, &ctx));
132:       PetscCall((*kdm->ops->ifunctionview)(ctx, viewer));
133:     }
134:     jacstruct.ijacobian         = kdm->ops->ijacobian;
135:     jacviewstruct.ijacobianview = kdm->ops->ijacobianview;
136:     jacloadstruct.ijacobianload = kdm->ops->ijacobianload;
137:     PetscCall(PetscViewerBinaryWrite(viewer, &jacstruct, 1, PETSC_FUNCTION));
138:     PetscCall(PetscViewerBinaryWrite(viewer, &jacviewstruct, 1, PETSC_FUNCTION));
139:     PetscCall(PetscViewerBinaryWrite(viewer, &jacloadstruct, 1, PETSC_FUNCTION));
140:     if (kdm->ops->ijacobianview) {
141:       PetscCtx ctx;

143:       PetscCall(PetscContainerGetPointer(kdm->ijacobianctxcontainer, &ctx));
144:       PetscCall((*kdm->ops->ijacobianview)(ctx, viewer));
145:     }
146:   }
147:   PetscFunctionReturn(PETSC_SUCCESS);
148: }

150: static PetscErrorCode DMTSCreate(MPI_Comm comm, DMTS *kdm)
151: {
152:   PetscFunctionBegin;
153:   PetscCall(TSInitializePackage());
154:   PetscCall(PetscHeaderCreate(*kdm, DMTS_CLASSID, "DMTS", "DMTS", "DMTS", comm, DMTSDestroy, DMTSView));
155:   PetscFunctionReturn(PETSC_SUCCESS);
156: }

158: /* Attaches the DMTS to the coarse level.
159:  * Under what conditions should we copy versus duplicate?
160:  */
161: static PetscErrorCode DMCoarsenHook_DMTS(DM dm, DM dmc, PetscCtx ctx)
162: {
163:   PetscFunctionBegin;
164:   PetscCall(DMCopyDMTS(dm, dmc));
165:   PetscFunctionReturn(PETSC_SUCCESS);
166: }

168: /* This could restrict auxiliary information to the coarse level.
169:  */
170: static PetscErrorCode DMRestrictHook_DMTS(DM dm, Mat Restrict, Vec rscale, Mat Inject, DM dmc, PetscCtx ctx)
171: {
172:   PetscFunctionBegin;
173:   PetscFunctionReturn(PETSC_SUCCESS);
174: }

176: static PetscErrorCode DMSubDomainHook_DMTS(DM dm, DM subdm, PetscCtx ctx)
177: {
178:   PetscFunctionBegin;
179:   PetscCall(DMCopyDMTS(dm, subdm));
180:   PetscFunctionReturn(PETSC_SUCCESS);
181: }

183: /* This could restrict auxiliary information to the coarse level.
184:  */
185: static PetscErrorCode DMSubDomainRestrictHook_DMTS(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, PetscCtx ctx)
186: {
187:   PetscFunctionBegin;
188:   PetscFunctionReturn(PETSC_SUCCESS);
189: }

191: /*@
192:   DMTSCopy - copies the information in a `DMTS` to another `DMTS`

194:   Not Collective

196:   Input Parameters:
197: + kdm  - Original `DMTS`
198: - nkdm - `DMTS` to receive the data, should have been created with `DMTSCreate()`

200:   Level: developer

202: .seealso: [](ch_ts), `DMTSCreate()`, `DMTSDestroy()`
203: @*/
204: PetscErrorCode DMTSCopy(DMTS kdm, DMTS nkdm)
205: {
206:   PetscFunctionBegin;
209:   nkdm->ops->rhsfunction = kdm->ops->rhsfunction;
210:   nkdm->ops->rhsjacobian = kdm->ops->rhsjacobian;
211:   nkdm->ops->ifunction   = kdm->ops->ifunction;
212:   nkdm->ops->ijacobian   = kdm->ops->ijacobian;
213:   nkdm->ops->i2function  = kdm->ops->i2function;
214:   nkdm->ops->i2jacobian  = kdm->ops->i2jacobian;
215:   nkdm->ops->solution    = kdm->ops->solution;
216:   nkdm->ops->destroy     = kdm->ops->destroy;
217:   nkdm->ops->duplicate   = kdm->ops->duplicate;

219:   nkdm->solutionctx             = kdm->solutionctx;
220:   nkdm->rhsfunctionctxcontainer = kdm->rhsfunctionctxcontainer;
221:   nkdm->rhsjacobianctxcontainer = kdm->rhsjacobianctxcontainer;
222:   nkdm->ifunctionctxcontainer   = kdm->ifunctionctxcontainer;
223:   nkdm->ijacobianctxcontainer   = kdm->ijacobianctxcontainer;
224:   nkdm->i2functionctxcontainer  = kdm->i2functionctxcontainer;
225:   nkdm->i2jacobianctxcontainer  = kdm->i2jacobianctxcontainer;
226:   if (nkdm->rhsfunctionctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "rhs function ctx", (PetscObject)nkdm->rhsfunctionctxcontainer));
227:   if (nkdm->rhsjacobianctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "rhs jacobian ctx", (PetscObject)nkdm->rhsjacobianctxcontainer));
228:   if (nkdm->ifunctionctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "ifunction ctx", (PetscObject)nkdm->ifunctionctxcontainer));
229:   if (nkdm->ijacobianctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "ijacobian ctx", (PetscObject)nkdm->ijacobianctxcontainer));
230:   if (nkdm->i2functionctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "i2function ctx", (PetscObject)nkdm->i2functionctxcontainer));
231:   if (nkdm->i2jacobianctxcontainer) PetscCall(PetscObjectCompose((PetscObject)nkdm, "i2jacobian ctx", (PetscObject)nkdm->i2jacobianctxcontainer));

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

235:   /*
236:   nkdm->fortran_func_pointers[0] = kdm->fortran_func_pointers[0];
237:   nkdm->fortran_func_pointers[1] = kdm->fortran_func_pointers[1];
238:   nkdm->fortran_func_pointers[2] = kdm->fortran_func_pointers[2];
239:   */

241:   /* implementation specific copy hooks */
242:   PetscTryTypeMethod(kdm, duplicate, nkdm);
243:   PetscFunctionReturn(PETSC_SUCCESS);
244: }

246: /*@
247:   DMGetDMTS - get read-only private `DMTS` context from a `DM`

249:   Not Collective

251:   Input Parameter:
252: . dm - `DM` to be used with `TS`

254:   Output Parameter:
255: . tsdm - private `DMTS` context

257:   Level: developer

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

262: .seealso: [](ch_ts), `DMTS`, `DMGetDMTSWrite()`
263: @*/
264: PetscErrorCode DMGetDMTS(DM dm, DMTS *tsdm)
265: {
266:   PetscFunctionBegin;
268:   *tsdm = (DMTS)dm->dmts;
269:   if (!*tsdm) {
270:     PetscCall(PetscInfo(dm, "Creating new DMTS\n"));
271:     PetscCall(DMTSCreate(PetscObjectComm((PetscObject)dm), tsdm));
272:     dm->dmts            = (PetscObject)*tsdm;
273:     (*tsdm)->originaldm = dm;
274:     PetscCall(DMCoarsenHookAdd(dm, DMCoarsenHook_DMTS, DMRestrictHook_DMTS, NULL));
275:     PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_DMTS, DMSubDomainRestrictHook_DMTS, NULL));
276:   }
277:   PetscFunctionReturn(PETSC_SUCCESS);
278: }

280: /*@
281:   DMGetDMTSWrite - get write access to private `DMTS` context from a `DM`

283:   Not Collective

285:   Input Parameter:
286: . dm - `DM` to be used with `TS`

288:   Output Parameter:
289: . tsdm - private `DMTS` context

291:   Level: developer

293: .seealso: [](ch_ts), `DMTS`, `DMGetDMTS()`
294: @*/
295: PetscErrorCode DMGetDMTSWrite(DM dm, DMTS *tsdm)
296: {
297:   DMTS sdm;

299:   PetscFunctionBegin;
301:   PetscCall(DMGetDMTS(dm, &sdm));
302:   PetscCheck(sdm->originaldm, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DMTS has a NULL originaldm");
303:   if (sdm->originaldm != dm) { /* Copy on write */
304:     DMTS oldsdm = sdm;
305:     PetscCall(PetscInfo(dm, "Copying DMTS due to write\n"));
306:     PetscCall(DMTSCreate(PetscObjectComm((PetscObject)dm), &sdm));
307:     PetscCall(DMTSCopy(oldsdm, sdm));
308:     PetscCall(DMTSDestroy((DMTS *)&dm->dmts));
309:     dm->dmts        = (PetscObject)sdm;
310:     sdm->originaldm = dm;
311:   }
312:   *tsdm = sdm;
313:   PetscFunctionReturn(PETSC_SUCCESS);
314: }

316: /*@
317:   DMCopyDMTS - copies a `DMTS` context to a new `DM`

319:   Logically Collective

321:   Input Parameters:
322: + dmsrc  - `DM` to obtain context from
323: - dmdest - `DM` to add context to

325:   Level: developer

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

330: .seealso: [](ch_ts), `DMTS`, `DMGetDMTS()`, `TSSetDM()`
331: @*/
332: PetscErrorCode DMCopyDMTS(DM dmsrc, DM dmdest)
333: {
334:   PetscFunctionBegin;
337:   PetscCall(DMTSDestroy((DMTS *)&dmdest->dmts));
338:   dmdest->dmts = dmsrc->dmts;
339:   PetscCall(PetscObjectReference(dmdest->dmts));
340:   PetscCall(DMCoarsenHookAdd(dmdest, DMCoarsenHook_DMTS, DMRestrictHook_DMTS, NULL));
341:   PetscCall(DMSubDomainHookAdd(dmdest, DMSubDomainHook_DMTS, DMSubDomainRestrictHook_DMTS, NULL));
342:   PetscFunctionReturn(PETSC_SUCCESS);
343: }

345: /*@
346:   DMTSSetIFunction - set `TS` implicit function evaluation function into a `DMTS`

348:   Not Collective

350:   Input Parameters:
351: + dm   - `DM` to be used with `TS`
352: . func - function evaluating f(t,u,u_t)
353: - ctx  - context for residual evaluation

355:   Level: developer

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

362: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSIFunctionFn`
363: @*/
364: PetscErrorCode DMTSSetIFunction(DM dm, TSIFunctionFn *func, PetscCtx ctx)
365: {
366:   DMTS tsdm;

368:   PetscFunctionBegin;
370:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
371:   if (func) tsdm->ops->ifunction = func;
372:   if (ctx) {
373:     PetscContainer ctxcontainer;
374:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
375:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
376:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "ifunction ctx", (PetscObject)ctxcontainer));
377:     tsdm->ifunctionctxcontainer = ctxcontainer;
378:     PetscCall(PetscContainerDestroy(&ctxcontainer));
379:   }
380:   PetscFunctionReturn(PETSC_SUCCESS);
381: }

383: /*@
384:   DMTSSetIFunctionContextDestroy - set `TS` implicit evaluation context destroy function into a `DMTS`

386:   Not Collective

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

392:   Level: developer

394: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetIFunction()`, `TSSetIFunction()`, `PetscCtxDestroyFn`
395: @*/
396: PetscErrorCode DMTSSetIFunctionContextDestroy(DM dm, PetscCtxDestroyFn *f)
397: {
398:   DMTS tsdm;

400:   PetscFunctionBegin;
402:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
403:   if (tsdm->ifunctionctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->ifunctionctxcontainer, f));
404:   PetscFunctionReturn(PETSC_SUCCESS);
405: }

407: PetscErrorCode DMTSUnsetIFunctionContext_Internal(DM dm)
408: {
409:   DMTS tsdm;

411:   PetscFunctionBegin;
413:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
414:   PetscCall(DMTSUnsetIFunctionContext_DMTS(tsdm));
415:   PetscFunctionReturn(PETSC_SUCCESS);
416: }

418: /*@
419:   DMTSGetIFunction - get `TS` implicit residual evaluation function from a `DMTS`

421:   Not Collective

423:   Input Parameter:
424: . dm - `DM` to be used with `TS`

426:   Output Parameters:
427: + func - function evaluation function, for calling sequence see `TSIFunctionFn`
428: - ctx  - context for residual evaluation

430:   Level: developer

432:   Note:
433:   `TSGetIFunction()` is normally used, but it calls this function internally because the application context is actually
434:   associated with the `DM`.

436: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `DMTSSetIFunction()`, `TSIFunctionFn`
437: @*/
438: PetscErrorCode DMTSGetIFunction(DM dm, TSIFunctionFn **func, PetscCtxRt ctx)
439: {
440:   DMTS tsdm;

442:   PetscFunctionBegin;
444:   PetscCall(DMGetDMTS(dm, &tsdm));
445:   if (func) *func = tsdm->ops->ifunction;
446:   if (ctx) {
447:     if (tsdm->ifunctionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->ifunctionctxcontainer, ctx));
448:     else *(void **)ctx = NULL;
449:   }
450:   PetscFunctionReturn(PETSC_SUCCESS);
451: }

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

456:   Not Collective

458:   Input Parameters:
459: + dm  - `DM` to be used with `TS`
460: . fun - function evaluation routine
461: - ctx - context for residual evaluation

463:   Level: developer

465:   Note:
466:   `TSSetI2Function()` is normally used, but it calls this function internally because the application context is actually
467:   associated with the `DM`.

469: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSSetI2Function()`
470: @*/
471: PetscErrorCode DMTSSetI2Function(DM dm, TSI2FunctionFn *fun, PetscCtx ctx)
472: {
473:   DMTS tsdm;

475:   PetscFunctionBegin;
477:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
478:   if (fun) tsdm->ops->i2function = fun;
479:   if (ctx) {
480:     PetscContainer ctxcontainer;
481:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
482:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
483:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "i2function ctx", (PetscObject)ctxcontainer));
484:     tsdm->i2functionctxcontainer = ctxcontainer;
485:     PetscCall(PetscContainerDestroy(&ctxcontainer));
486:   }
487:   PetscFunctionReturn(PETSC_SUCCESS);
488: }

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

493:   Not Collective

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

499:   Level: developer

501:   Note:
502:   `TSSetI2FunctionContextDestroy()` is normally used, but it calls this function internally because the application context is actually
503:   associated with the `DM`.

505: .seealso: [](ch_ts), `DMTS`, `TSSetI2FunctionContextDestroy()`, `DMTSSetI2Function()`, `TSSetI2Function()`
506: @*/
507: PetscErrorCode DMTSSetI2FunctionContextDestroy(DM dm, PetscCtxDestroyFn *f)
508: {
509:   DMTS tsdm;

511:   PetscFunctionBegin;
513:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
514:   if (tsdm->i2functionctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->i2functionctxcontainer, f));
515:   PetscFunctionReturn(PETSC_SUCCESS);
516: }

518: PetscErrorCode DMTSUnsetI2FunctionContext_Internal(DM dm)
519: {
520:   DMTS tsdm;

522:   PetscFunctionBegin;
524:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
525:   PetscCall(DMTSUnsetI2FunctionContext_DMTS(tsdm));
526:   PetscFunctionReturn(PETSC_SUCCESS);
527: }

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

532:   Not Collective

534:   Input Parameter:
535: . dm - `DM` to be used with `TS`

537:   Output Parameters:
538: + fun - function evaluation function, for calling sequence see `TSSetI2Function()`
539: - ctx - context for residual evaluation

541:   Level: developer

543:   Note:
544:   `TSGetI2Function()` is normally used, but it calls this function internally because the application context is actually
545:   associated with the `DM`.

547: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetI2Function()`, `TSGetI2Function()`
548: @*/
549: PetscErrorCode DMTSGetI2Function(DM dm, TSI2FunctionFn **fun, PetscCtxRt ctx)
550: {
551:   DMTS tsdm;

553:   PetscFunctionBegin;
555:   PetscCall(DMGetDMTS(dm, &tsdm));
556:   if (fun) *fun = tsdm->ops->i2function;
557:   if (ctx) {
558:     if (tsdm->i2functionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->i2functionctxcontainer, ctx));
559:     else *(void **)ctx = NULL;
560:   }
561:   PetscFunctionReturn(PETSC_SUCCESS);
562: }

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

567:   Not Collective

569:   Input Parameters:
570: + dm  - `DM` to be used with `TS`
571: . jac - Jacobian evaluation routine
572: - ctx - context for Jacobian evaluation

574:   Level: developer

576:   Note:
577:   `TSSetI2Jacobian()` is normally used, but it calls this function internally because the application context is actually
578:   associated with the `DM`.

580: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSI2JacobianFn`, `TSSetI2Jacobian()`
581: @*/
582: PetscErrorCode DMTSSetI2Jacobian(DM dm, TSI2JacobianFn *jac, PetscCtx ctx)
583: {
584:   DMTS tsdm;

586:   PetscFunctionBegin;
588:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
589:   if (jac) tsdm->ops->i2jacobian = jac;
590:   if (ctx) {
591:     PetscContainer ctxcontainer;
592:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
593:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
594:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "i2jacobian ctx", (PetscObject)ctxcontainer));
595:     tsdm->i2jacobianctxcontainer = ctxcontainer;
596:     PetscCall(PetscContainerDestroy(&ctxcontainer));
597:   }
598:   PetscFunctionReturn(PETSC_SUCCESS);
599: }

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

604:   Not Collective

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

610:   Level: developer

612:   Note:
613:   Normally `TSSetI2JacobianContextDestroy()` is used

615: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSSetI2JacobianContextDestroy()`, `DMTSSetI2Jacobian()`, `TSSetI2Jacobian()`
616: @*/
617: PetscErrorCode DMTSSetI2JacobianContextDestroy(DM dm, PetscCtxDestroyFn *f)
618: {
619:   DMTS tsdm;

621:   PetscFunctionBegin;
623:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
624:   if (tsdm->i2jacobianctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->i2jacobianctxcontainer, f));
625:   PetscFunctionReturn(PETSC_SUCCESS);
626: }

628: PetscErrorCode DMTSUnsetI2JacobianContext_Internal(DM dm)
629: {
630:   DMTS tsdm;

632:   PetscFunctionBegin;
634:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
635:   PetscCall(DMTSUnsetI2JacobianContext_DMTS(tsdm));
636:   PetscFunctionReturn(PETSC_SUCCESS);
637: }

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

642:   Not Collective

644:   Input Parameter:
645: . dm - `DM` to be used with `TS`

647:   Output Parameters:
648: + jac - Jacobian evaluation function,  for calling sequence see `TSI2JacobianFn`
649: - ctx - context for Jacobian evaluation

651:   Level: developer

653:   Note:
654:   `TSGetI2Jacobian()` is normally used, but it calls this function internally because the application context is actually
655:   associated with the `DM`.

657: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetI2Jacobian()`, `TSGetI2Jacobian()`, `TSI2JacobianFn`
658: @*/
659: PetscErrorCode DMTSGetI2Jacobian(DM dm, TSI2JacobianFn **jac, PetscCtxRt ctx)
660: {
661:   DMTS tsdm;

663:   PetscFunctionBegin;
665:   PetscCall(DMGetDMTS(dm, &tsdm));
666:   if (jac) *jac = tsdm->ops->i2jacobian;
667:   if (ctx) {
668:     if (tsdm->i2jacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->i2jacobianctxcontainer, ctx));
669:     else *(void **)ctx = NULL;
670:   }
671:   PetscFunctionReturn(PETSC_SUCCESS);
672: }

674: /*@
675:   DMTSSetRHSFunction - set `TS` explicit residual evaluation function into a `DMTS`

677:   Not Collective

679:   Input Parameters:
680: + dm   - `DM` to be used with `TS`
681: . func - RHS function evaluation routine, see `TSRHSFunctionFn` for the calling sequence
682: - ctx  - context for residual evaluation

684:   Level: developer

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

691: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSRHSFunctionFn`
692: @*/
693: PetscErrorCode DMTSSetRHSFunction(DM dm, TSRHSFunctionFn *func, PetscCtx ctx)
694: {
695:   DMTS tsdm;

697:   PetscFunctionBegin;
699:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
700:   if (func) tsdm->ops->rhsfunction = func;
701:   if (ctx) {
702:     PetscContainer ctxcontainer;
703:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
704:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
705:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "rhs function ctx", (PetscObject)ctxcontainer));
706:     tsdm->rhsfunctionctxcontainer = ctxcontainer;
707:     PetscCall(PetscContainerDestroy(&ctxcontainer));
708:   }
709:   PetscFunctionReturn(PETSC_SUCCESS);
710: }

712: /*@
713:   DMTSSetRHSFunctionContextDestroy - set `TS` explicit residual evaluation context destroy function into a `DMTS`

715:   Not Collective

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

721:   Level: developer

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

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

731: .seealso: [](ch_ts), `DMTS`, `TSSetRHSFunctionContextDestroy()`, `DMTSSetRHSFunction()`, `TSSetRHSFunction()`
732: @*/
733: PetscErrorCode DMTSSetRHSFunctionContextDestroy(DM dm, PetscCtxDestroyFn *f)
734: {
735:   DMTS tsdm;

737:   PetscFunctionBegin;
739:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
740:   if (tsdm->rhsfunctionctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->rhsfunctionctxcontainer, f));
741:   PetscFunctionReturn(PETSC_SUCCESS);
742: }

744: PetscErrorCode DMTSUnsetRHSFunctionContext_Internal(DM dm)
745: {
746:   DMTS tsdm;

748:   PetscFunctionBegin;
750:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
751:   PetscCall(DMTSUnsetRHSFunctionContext_DMTS(tsdm));
752:   tsdm->rhsfunctionctxcontainer = NULL;
753:   PetscFunctionReturn(PETSC_SUCCESS);
754: }

756: /*@
757:   DMTSSetTransientVariable - sets function to transform from state to transient variables into a `DMTS`

759:   Logically Collective

761:   Input Parameters:
762: + dm   - `DM` to be used with `TS`
763: . tvar - a function that transforms to transient variables, see `TSTransientVariableFn` for the calling sequence
764: - ctx  - a context for tvar

766:   Level: developer

768:   Notes:
769:   Normally `TSSetTransientVariable()` is used

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

777:   $$
778:   dF/dP + shift dF/dCdot dC/dP.
779:   $$

781: .seealso: [](ch_ts), `DMTS`, `TS`, `TSBDF`, `TSSetTransientVariable()`, `DMTSGetTransientVariable()`, `DMTSSetIFunction()`, `DMTSSetIJacobian()`, `TSTransientVariableFn`
782: @*/
783: PetscErrorCode DMTSSetTransientVariable(DM dm, TSTransientVariableFn *tvar, PetscCtx ctx)
784: {
785:   DMTS dmts;

787:   PetscFunctionBegin;
789:   PetscCall(DMGetDMTSWrite(dm, &dmts));
790:   dmts->ops->transientvar = tvar;
791:   dmts->transientvarctx   = ctx;
792:   PetscFunctionReturn(PETSC_SUCCESS);
793: }

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

798:   Logically Collective

800:   Input Parameter:
801: . dm - `DM` to be used with `TS`

803:   Output Parameters:
804: + tvar - a function that transforms to transient variables, see `TSTransientVariableFn` for the calling sequence
805: - ctx  - a context for tvar

807:   Level: developer

809:   Note:
810:   Normally `TSSetTransientVariable()` is used

812: .seealso: [](ch_ts), `DMTS`, `DM`, `DMTSSetTransientVariable()`, `DMTSGetIFunction()`, `DMTSGetIJacobian()`, `TSTransientVariableFn`
813: @*/
814: PetscErrorCode DMTSGetTransientVariable(DM dm, TSTransientVariableFn **tvar, PetscCtx ctx)
815: {
816:   DMTS dmts;

818:   PetscFunctionBegin;
820:   PetscCall(DMGetDMTS(dm, &dmts));
821:   if (tvar) *tvar = dmts->ops->transientvar;
822:   if (ctx) *(void **)ctx = dmts->transientvarctx;
823:   PetscFunctionReturn(PETSC_SUCCESS);
824: }

826: /*@
827:   DMTSGetSolutionFunction - gets the `TS` solution evaluation function from a `DMTS`

829:   Not Collective

831:   Input Parameter:
832: . dm - `DM` to be used with `TS`

834:   Output Parameters:
835: + func - solution function evaluation function, for calling sequence see `TSSolutionFn`
836: - ctx  - context for solution evaluation

838:   Level: developer

840: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `DMTSSetSolutionFunction()`, `TSSolutionFn`
841: @*/
842: PetscErrorCode DMTSGetSolutionFunction(DM dm, TSSolutionFn **func, PetscCtxRt ctx)
843: {
844:   DMTS tsdm;

846:   PetscFunctionBegin;
848:   PetscCall(DMGetDMTS(dm, &tsdm));
849:   if (func) *func = tsdm->ops->solution;
850:   if (ctx) *(void **)ctx = tsdm->solutionctx;
851:   PetscFunctionReturn(PETSC_SUCCESS);
852: }

854: /*@
855:   DMTSSetSolutionFunction - set `TS` solution evaluation function into a `DMTS`

857:   Not Collective

859:   Input Parameters:
860: + dm   - `DM` to be used with `TS`
861: . func - solution function evaluation routine, for calling sequence see `TSSolutionFn`
862: - ctx  - context for solution evaluation

864:   Level: developer

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

871: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSGetSolutionFunction()`, `TSSolutionFn`
872: @*/
873: PetscErrorCode DMTSSetSolutionFunction(DM dm, TSSolutionFn *func, PetscCtx ctx)
874: {
875:   DMTS tsdm;

877:   PetscFunctionBegin;
879:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
880:   if (func) tsdm->ops->solution = func;
881:   if (ctx) tsdm->solutionctx = ctx;
882:   PetscFunctionReturn(PETSC_SUCCESS);
883: }

885: /*@
886:   DMTSSetForcingFunction - set `TS` forcing function evaluation function into a `DMTS`

888:   Not Collective

890:   Input Parameters:
891: + dm   - `DM` to be used with `TS`
892: . func - forcing function evaluation routine, for calling sequence see `TSForcingFn`
893: - ctx  - context for solution evaluation

895:   Level: developer

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

902: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSForcingFn`, `TSSetForcingFunction()`, `DMTSGetForcingFunction()`
903: @*/
904: PetscErrorCode DMTSSetForcingFunction(DM dm, TSForcingFn *func, PetscCtx ctx)
905: {
906:   DMTS tsdm;

908:   PetscFunctionBegin;
910:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
911:   if (func) tsdm->ops->forcing = func;
912:   if (ctx) tsdm->forcingctx = ctx;
913:   PetscFunctionReturn(PETSC_SUCCESS);
914: }

916: /*@
917:   DMTSGetForcingFunction - get `TS` forcing function evaluation function from a `DMTS`

919:   Not Collective

921:   Input Parameter:
922: . dm - `DM` to be used with `TS`

924:   Output Parameters:
925: + f   - forcing function evaluation function; see `TSForcingFn` for the calling sequence
926: - ctx - context for solution evaluation

928:   Level: developer

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

935: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSSetForcingFunction()`, `TSForcingFn`
936: @*/
937: PetscErrorCode DMTSGetForcingFunction(DM dm, TSForcingFn **f, PetscCtxRt ctx)
938: {
939:   DMTS tsdm;

941:   PetscFunctionBegin;
943:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
944:   if (f) *f = tsdm->ops->forcing;
945:   if (ctx) *(void **)ctx = tsdm->forcingctx;
946:   PetscFunctionReturn(PETSC_SUCCESS);
947: }

949: /*@
950:   DMTSGetRHSFunction - get `TS` explicit residual evaluation function from a `DMTS`

952:   Not Collective

954:   Input Parameter:
955: . dm - `DM` to be used with `TS`

957:   Output Parameters:
958: + func - residual evaluation function, for calling sequence see `TSRHSFunctionFn`
959: - ctx  - context for residual evaluation

961:   Level: developer

963:   Note:
964:   `TSGetRHSFunction()` is normally used, but it calls this function internally because the application context is actually
965:   associated with the DM.

967: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSRHSFunctionFn`, `TSGetRHSFunction()`
968: @*/
969: PetscErrorCode DMTSGetRHSFunction(DM dm, TSRHSFunctionFn **func, PetscCtxRt ctx)
970: {
971:   DMTS tsdm;

973:   PetscFunctionBegin;
975:   PetscCall(DMGetDMTS(dm, &tsdm));
976:   if (func) *func = tsdm->ops->rhsfunction;
977:   if (ctx) {
978:     if (tsdm->rhsfunctionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->rhsfunctionctxcontainer, ctx));
979:     else *(void **)ctx = NULL;
980:   }
981:   PetscFunctionReturn(PETSC_SUCCESS);
982: }

984: /*@
985:   DMTSSetIJacobian - set `TS` Jacobian evaluation function into a `DMTS`

987:   Not Collective

989:   Input Parameters:
990: + dm   - `DM` to be used with `TS`
991: . func - Jacobian evaluation routine, see `TSIJacobianFn` for the calling sequence
992: - ctx  - context for residual evaluation

994:   Level: developer

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

1001: .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSIJacobianFn`, `DMTSGetIJacobian()`, `TSSetIJacobian()`
1002: @*/
1003: PetscErrorCode DMTSSetIJacobian(DM dm, TSIJacobianFn *func, PetscCtx ctx)
1004: {
1005:   DMTS tsdm;

1007:   PetscFunctionBegin;
1009:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1010:   if (func) tsdm->ops->ijacobian = func;
1011:   if (ctx) {
1012:     PetscContainer ctxcontainer;
1013:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
1014:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1015:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "ijacobian ctx", (PetscObject)ctxcontainer));
1016:     tsdm->ijacobianctxcontainer = ctxcontainer;
1017:     PetscCall(PetscContainerDestroy(&ctxcontainer));
1018:   }
1019:   PetscFunctionReturn(PETSC_SUCCESS);
1020: }

1022: /*@
1023:   DMTSSetIJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function into a `DMTS`

1025:   Not Collective

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

1031:   Level: developer

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

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

1041: .seealso: [](ch_ts), `DMTS`, `TSSetIJacobianContextDestroy()`, `TSSetI2JacobianContextDestroy()`, `DMTSSetIJacobian()`, `TSSetIJacobian()`
1042: @*/
1043: PetscErrorCode DMTSSetIJacobianContextDestroy(DM dm, PetscCtxDestroyFn *f)
1044: {
1045:   DMTS tsdm;

1047:   PetscFunctionBegin;
1049:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1050:   if (tsdm->ijacobianctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->ijacobianctxcontainer, f));
1051:   PetscFunctionReturn(PETSC_SUCCESS);
1052: }

1054: PetscErrorCode DMTSUnsetIJacobianContext_Internal(DM dm)
1055: {
1056:   DMTS tsdm;

1058:   PetscFunctionBegin;
1060:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1061:   PetscCall(DMTSUnsetIJacobianContext_DMTS(tsdm));
1062:   PetscFunctionReturn(PETSC_SUCCESS);
1063: }

1065: /*@
1066:   DMTSGetIJacobian - get `TS` Jacobian evaluation function from a `DMTS`

1068:   Not Collective

1070:   Input Parameter:
1071: . dm - `DM` to be used with `TS`

1073:   Output Parameters:
1074: + func - Jacobian evaluation function, for calling sequence see `TSIJacobianFn`
1075: - ctx  - context for residual evaluation

1077:   Level: developer

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

1084: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetIJacobian()`, `TSIJacobianFn`
1085: @*/
1086: PetscErrorCode DMTSGetIJacobian(DM dm, TSIJacobianFn **func, PetscCtxRt ctx)
1087: {
1088:   DMTS tsdm;

1090:   PetscFunctionBegin;
1092:   PetscCall(DMGetDMTS(dm, &tsdm));
1093:   if (func) *func = tsdm->ops->ijacobian;
1094:   if (ctx) {
1095:     if (tsdm->ijacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->ijacobianctxcontainer, ctx));
1096:     else *(void **)ctx = NULL;
1097:   }
1098:   PetscFunctionReturn(PETSC_SUCCESS);
1099: }

1101: /*@
1102:   DMTSSetRHSJacobian - set `TS` Jacobian evaluation function into a `DMTS`

1104:   Not Collective

1106:   Input Parameters:
1107: + dm   - `DM` to be used with `TS`
1108: . func - Jacobian evaluation routine, for calling sequence see `TSIJacobianFn`
1109: - ctx  - context for residual evaluation

1111:   Level: developer

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

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

1121: .seealso: [](ch_ts), `DMTS`, `TSRHSJacobianFn`, `DMTSGetRHSJacobian()`, `TSSetRHSJacobian()`
1122: @*/
1123: PetscErrorCode DMTSSetRHSJacobian(DM dm, TSRHSJacobianFn *func, PetscCtx ctx)
1124: {
1125:   DMTS tsdm;

1127:   PetscFunctionBegin;
1129:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1130:   if (func) tsdm->ops->rhsjacobian = func;
1131:   if (ctx) {
1132:     PetscContainer ctxcontainer;
1133:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
1134:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1135:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "rhs jacobian ctx", (PetscObject)ctxcontainer));
1136:     tsdm->rhsjacobianctxcontainer = ctxcontainer;
1137:     PetscCall(PetscContainerDestroy(&ctxcontainer));
1138:   }
1139:   PetscFunctionReturn(PETSC_SUCCESS);
1140: }

1142: /*@
1143:   DMTSSetRHSJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function from a `DMTS`

1145:   Not Collective

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

1151:   Level: developer

1153:   Note:
1154:   The user usually calls `TSSetRHSJacobianContextDestroy()` which calls this routine

1156: .seealso: [](ch_ts), `DMTS`, `TS`, `TSSetRHSJacobianContextDestroy()`, `DMTSSetRHSJacobian()`, `TSSetRHSJacobian()`
1157: @*/
1158: PetscErrorCode DMTSSetRHSJacobianContextDestroy(DM dm, PetscCtxDestroyFn *f)
1159: {
1160:   DMTS tsdm;

1162:   PetscFunctionBegin;
1164:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1165:   if (tsdm->rhsjacobianctxcontainer) PetscCall(PetscContainerSetCtxDestroy(tsdm->rhsjacobianctxcontainer, f));
1166:   PetscFunctionReturn(PETSC_SUCCESS);
1167: }

1169: PetscErrorCode DMTSUnsetRHSJacobianContext_Internal(DM dm)
1170: {
1171:   DMTS tsdm;

1173:   PetscFunctionBegin;
1175:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1176:   PetscCall(DMTSUnsetRHSJacobianContext_DMTS(tsdm));
1177:   PetscFunctionReturn(PETSC_SUCCESS);
1178: }

1180: /*@
1181:   DMTSGetRHSJacobian - get `TS` Jacobian evaluation function from a `DMTS`

1183:   Not Collective

1185:   Input Parameter:
1186: . dm - `DM` to be used with `TS`

1188:   Output Parameters:
1189: + func - Jacobian evaluation function, for calling sequence see `TSRHSJacobianFn`
1190: - ctx  - context for residual evaluation

1192:   Level: developer

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

1199: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetRHSJacobian()`, `TSRHSJacobianFn`
1200: @*/
1201: PetscErrorCode DMTSGetRHSJacobian(DM dm, TSRHSJacobianFn **func, PetscCtxRt ctx)
1202: {
1203:   DMTS tsdm;

1205:   PetscFunctionBegin;
1207:   PetscCall(DMGetDMTS(dm, &tsdm));
1208:   if (func) *func = tsdm->ops->rhsjacobian;
1209:   if (ctx) {
1210:     if (tsdm->rhsjacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->rhsjacobianctxcontainer, ctx));
1211:     else *(void **)ctx = NULL;
1212:   }
1213:   PetscFunctionReturn(PETSC_SUCCESS);
1214: }

1216: /*@
1217:   DMTSSetIFunctionSerialize - sets functions used to view and load a `TSIFunctionFn` context

1219:   Not Collective

1221:   Input Parameters:
1222: + dm   - `DM` to be used with `TS`
1223: . view - viewer function
1224: - load - loading function

1226:   Level: developer

1228: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`
1229: @*/
1230: PetscErrorCode DMTSSetIFunctionSerialize(DM dm, PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*load)(void **, PetscViewer))
1231: {
1232:   DMTS tsdm;

1234:   PetscFunctionBegin;
1236:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1237:   tsdm->ops->ifunctionview = view;
1238:   tsdm->ops->ifunctionload = load;
1239:   PetscFunctionReturn(PETSC_SUCCESS);
1240: }

1242: /*@
1243:   DMTSSetIJacobianSerialize - sets functions used to view and load a `TSIJacobianFn` context

1245:   Not Collective

1247:   Input Parameters:
1248: + dm   - `DM` to be used with `TS`
1249: . view - viewer function
1250: - load - loading function

1252:   Level: developer

1254: .seealso: [](ch_ts), `DMTS`, `DM`, `TS`
1255: @*/
1256: PetscErrorCode DMTSSetIJacobianSerialize(DM dm, PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*load)(void **, PetscViewer))
1257: {
1258:   DMTS tsdm;

1260:   PetscFunctionBegin;
1262:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1263:   tsdm->ops->ijacobianview = view;
1264:   tsdm->ops->ijacobianload = load;
1265:   PetscFunctionReturn(PETSC_SUCCESS);
1266: }