xref: /petsc/src/ts/utils/dmts.c (revision 4ad8454beace47809662cdae21ee081016eaa39a)
1 #include <petsc/private/tsimpl.h> /*I "petscts.h" I*/
2 #include <petsc/private/dmimpl.h>
3 
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 }
11 
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 }
19 
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 }
27 
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 }
35 
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 }
43 
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 }
51 
52 static PetscErrorCode DMTSDestroy(DMTS *kdm)
53 {
54   PetscFunctionBegin;
55   if (!*kdm) PetscFunctionReturn(PETSC_SUCCESS);
56   PetscValidHeaderSpecific(*kdm, DMTS_CLASSID, 1);
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 }
71 
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;
80 
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;
89 
90     PetscCall(PetscContainerGetPointer(kdm->ijacobianctxcontainer, &ctx));
91     PetscCall((*kdm->ops->ijacobianload)(&ctx, viewer));
92   }
93   PetscFunctionReturn(PETSC_SUCCESS);
94 }
95 
96 PetscErrorCode DMTSView(DMTS kdm, PetscViewer viewer)
97 {
98   PetscBool isascii, isbinary;
99 
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;
106 
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;
131 
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;
140 
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;
152 
153       PetscCall(PetscContainerGetPointer(kdm->ijacobianctxcontainer, &ctx));
154       PetscCall((*kdm->ops->ijacobianview)(ctx, viewer));
155     }
156   }
157   PetscFunctionReturn(PETSC_SUCCESS);
158 }
159 
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 }
167 
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 }
177 
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 }
185 
186 static PetscErrorCode DMSubDomainHook_DMTS(DM dm, DM subdm, void *ctx)
187 {
188   PetscFunctionBegin;
189   PetscCall(DMCopyDMTS(dm, subdm));
190   PetscFunctionReturn(PETSC_SUCCESS);
191 }
192 
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 }
200 
201 /*@C
202   DMTSCopy - copies the information in a `DMTS` to another `DMTS`
203 
204   Not Collective
205 
206   Input Parameters:
207 + kdm  - Original `DMTS`
208 - nkdm - `DMTS` to receive the data, should have been created with `DMTSCreate()`
209 
210   Level: developer
211 
212 .seealso: [](ch_ts), `DMTSCreate()`, `DMTSDestroy()`
213 @*/
214 PetscErrorCode DMTSCopy(DMTS kdm, DMTS nkdm)
215 {
216   PetscFunctionBegin;
217   PetscValidHeaderSpecific(kdm, DMTS_CLASSID, 1);
218   PetscValidHeaderSpecific(nkdm, DMTS_CLASSID, 2);
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;
228 
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));
242 
243   nkdm->data = kdm->data;
244 
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   */
250 
251   /* implementation specific copy hooks */
252   PetscTryTypeMethod(kdm, duplicate, nkdm);
253   PetscFunctionReturn(PETSC_SUCCESS);
254 }
255 
256 /*@C
257   DMGetDMTS - get read-only private `DMTS` context from a `DM`
258 
259   Not Collective
260 
261   Input Parameter:
262 . dm - `DM` to be used with `TS`
263 
264   Output Parameter:
265 . tsdm - private `DMTS` context
266 
267   Level: developer
268 
269   Notes:
270   Use `DMGetDMTSWrite()` if write access is needed. The `DMTSSetXXX()` API should be used wherever possible.
271 
272 .seealso: [](ch_ts), `DMTS`, `DMGetDMTSWrite()`
273 @*/
274 PetscErrorCode DMGetDMTS(DM dm, DMTS *tsdm)
275 {
276   PetscFunctionBegin;
277   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
289 
290 /*@C
291   DMGetDMTSWrite - get write access to private `DMTS` context from a `DM`
292 
293   Not Collective
294 
295   Input Parameter:
296 . dm - `DM` to be used with `TS`
297 
298   Output Parameter:
299 . tsdm - private `DMTS` context
300 
301   Level: developer
302 
303 .seealso: [](ch_ts), `DMTS`, `DMGetDMTS()`
304 @*/
305 PetscErrorCode DMGetDMTSWrite(DM dm, DMTS *tsdm)
306 {
307   DMTS sdm;
308 
309   PetscFunctionBegin;
310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
325 
326 /*@C
327   DMCopyDMTS - copies a `DMTS` context to a new `DM`
328 
329   Logically Collective
330 
331   Input Parameters:
332 + dmsrc  - `DM` to obtain context from
333 - dmdest - `DM` to add context to
334 
335   Level: developer
336 
337   Note:
338   The context is copied by reference. This function does not ensure that a context exists.
339 
340 .seealso: [](ch_ts), `DMTS`, `DMGetDMTS()`, `TSSetDM()`
341 @*/
342 PetscErrorCode DMCopyDMTS(DM dmsrc, DM dmdest)
343 {
344   PetscFunctionBegin;
345   PetscValidHeaderSpecific(dmsrc, DM_CLASSID, 1);
346   PetscValidHeaderSpecific(dmdest, DM_CLASSID, 2);
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 }
354 
355 /*@C
356   DMTSSetIFunction - set `TS` implicit function evaluation function into a `DMTS`
357 
358   Not Collective
359 
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
364 
365   Level: developer
366 
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.
371 
372 .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSIFunctionFn`
373 @*/
374 PetscErrorCode DMTSSetIFunction(DM dm, TSIFunctionFn *func, void *ctx)
375 {
376   DMTS tsdm;
377 
378   PetscFunctionBegin;
379   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
392 
393 /*@C
394   DMTSSetIFunctionContextDestroy - set `TS` implicit evaluation context destroy function into a `DMTS`
395 
396   Not Collective
397 
398   Input Parameters:
399 + dm - `DM` to be used with `TS`
400 - f  - implicit evaluation context destroy function
401 
402   Level: developer
403 
404 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetIFunction()`, `TSSetIFunction()`
405 @*/
406 PetscErrorCode DMTSSetIFunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *))
407 {
408   DMTS tsdm;
409 
410   PetscFunctionBegin;
411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
412   PetscCall(DMGetDMTSWrite(dm, &tsdm));
413   if (tsdm->ifunctionctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->ifunctionctxcontainer, f));
414   PetscFunctionReturn(PETSC_SUCCESS);
415 }
416 
417 PetscErrorCode DMTSUnsetIFunctionContext_Internal(DM dm)
418 {
419   DMTS tsdm;
420 
421   PetscFunctionBegin;
422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
423   PetscCall(DMGetDMTSWrite(dm, &tsdm));
424   PetscCall(DMTSUnsetIFunctionContext_DMTS(tsdm));
425   PetscFunctionReturn(PETSC_SUCCESS);
426 }
427 
428 /*@C
429   DMTSGetIFunction - get `TS` implicit residual evaluation function from a `DMTS`
430 
431   Not Collective
432 
433   Input Parameter:
434 . dm - `DM` to be used with `TS`
435 
436   Output Parameters:
437 + func - function evaluation function, for calling sequence see `TSIFunctionFn`
438 - ctx  - context for residual evaluation
439 
440   Level: developer
441 
442   Note:
443   `TSGetIFunction()` is normally used, but it calls this function internally because the user context is actually
444   associated with the `DM`.
445 
446 .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `DMTSSetIFunction()`, `TSIFunctionFn`
447 @*/
448 PetscErrorCode DMTSGetIFunction(DM dm, TSIFunctionFn **func, void **ctx)
449 {
450   DMTS tsdm;
451 
452   PetscFunctionBegin;
453   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
462 
463 /*@C
464   DMTSSetI2Function - set `TS` implicit function evaluation function for 2nd order systems into a `TSDM`
465 
466   Not Collective
467 
468   Input Parameters:
469 + dm  - `DM` to be used with `TS`
470 . fun - function evaluation routine
471 - ctx - context for residual evaluation
472 
473   Level: developer
474 
475   Note:
476   `TSSetI2Function()` is normally used, but it calls this function internally because the user context is actually
477   associated with the `DM`.
478 
479 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSSetI2Function()`
480 @*/
481 PetscErrorCode DMTSSetI2Function(DM dm, TSI2FunctionFn *fun, void *ctx)
482 {
483   DMTS tsdm;
484 
485   PetscFunctionBegin;
486   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
499 
500 /*@C
501   DMTSSetI2FunctionContextDestroy - set `TS` implicit evaluation for 2nd order systems context destroy into a `DMTS`
502 
503   Not Collective
504 
505   Input Parameters:
506 + dm - `DM` to be used with `TS`
507 - f  - implicit evaluation context destroy function
508 
509   Level: developer
510 
511   Note:
512   `TSSetI2FunctionContextDestroy()` is normally used, but it calls this function internally because the user context is actually
513   associated with the `DM`.
514 
515 .seealso: [](ch_ts), `DMTS`, `TSSetI2FunctionContextDestroy()`, `DMTSSetI2Function()`, `TSSetI2Function()`
516 @*/
517 PetscErrorCode DMTSSetI2FunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *))
518 {
519   DMTS tsdm;
520 
521   PetscFunctionBegin;
522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
523   PetscCall(DMGetDMTSWrite(dm, &tsdm));
524   if (tsdm->i2functionctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->i2functionctxcontainer, f));
525   PetscFunctionReturn(PETSC_SUCCESS);
526 }
527 
528 PetscErrorCode DMTSUnsetI2FunctionContext_Internal(DM dm)
529 {
530   DMTS tsdm;
531 
532   PetscFunctionBegin;
533   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
534   PetscCall(DMGetDMTSWrite(dm, &tsdm));
535   PetscCall(DMTSUnsetI2FunctionContext_DMTS(tsdm));
536   PetscFunctionReturn(PETSC_SUCCESS);
537 }
538 
539 /*@C
540   DMTSGetI2Function - get `TS` implicit residual evaluation function for 2nd order systems from a `DMTS`
541 
542   Not Collective
543 
544   Input Parameter:
545 . dm - `DM` to be used with `TS`
546 
547   Output Parameters:
548 + fun - function evaluation function, for calling sequence see `TSSetI2Function()`
549 - ctx - context for residual evaluation
550 
551   Level: developer
552 
553   Note:
554   `TSGetI2Function()` is normally used, but it calls this function internally because the user context is actually
555   associated with the `DM`.
556 
557 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetI2Function()`, `TSGetI2Function()`
558 @*/
559 PetscErrorCode DMTSGetI2Function(DM dm, TSI2FunctionFn **fun, void **ctx)
560 {
561   DMTS tsdm;
562 
563   PetscFunctionBegin;
564   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
573 
574 /*@C
575   DMTSSetI2Jacobian - set `TS` implicit Jacobian evaluation function for 2nd order systems from a `DMTS`
576 
577   Not Collective
578 
579   Input Parameters:
580 + dm  - `DM` to be used with `TS`
581 . jac - Jacobian evaluation routine
582 - ctx - context for Jacobian evaluation
583 
584   Level: developer
585 
586   Note:
587   `TSSetI2Jacobian()` is normally used, but it calls this function internally because the user context is actually
588   associated with the `DM`.
589 
590 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSI2JacobianFn`, `TSSetI2Jacobian()`
591 @*/
592 PetscErrorCode DMTSSetI2Jacobian(DM dm, TSI2JacobianFn *jac, void *ctx)
593 {
594   DMTS tsdm;
595 
596   PetscFunctionBegin;
597   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
610 
611 /*@C
612   DMTSSetI2JacobianContextDestroy - set `TS` implicit Jacobian evaluation for 2nd order systems context destroy function into a `DMTS`
613 
614   Not Collective
615 
616   Input Parameters:
617 + dm - `DM` to be used with `TS`
618 - f  - implicit Jacobian evaluation context destroy function
619 
620   Level: developer
621 
622   Note:
623   Normally `TSSetI2JacobianContextDestroy()` is used
624 
625 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSSetI2JacobianContextDestroy()`, `DMTSSetI2Jacobian()`, `TSSetI2Jacobian()`
626 @*/
627 PetscErrorCode DMTSSetI2JacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
628 {
629   DMTS tsdm;
630 
631   PetscFunctionBegin;
632   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
633   PetscCall(DMGetDMTSWrite(dm, &tsdm));
634   if (tsdm->i2jacobianctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->i2jacobianctxcontainer, f));
635   PetscFunctionReturn(PETSC_SUCCESS);
636 }
637 
638 PetscErrorCode DMTSUnsetI2JacobianContext_Internal(DM dm)
639 {
640   DMTS tsdm;
641 
642   PetscFunctionBegin;
643   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
644   PetscCall(DMGetDMTSWrite(dm, &tsdm));
645   PetscCall(DMTSUnsetI2JacobianContext_DMTS(tsdm));
646   PetscFunctionReturn(PETSC_SUCCESS);
647 }
648 
649 /*@C
650   DMTSGetI2Jacobian - get `TS` implicit Jacobian evaluation function for 2nd order systems from a `DMTS`
651 
652   Not Collective
653 
654   Input Parameter:
655 . dm - `DM` to be used with `TS`
656 
657   Output Parameters:
658 + jac - Jacobian evaluation function,  for calling sequence see `TSI2JacobianFn`
659 - ctx - context for Jacobian evaluation
660 
661   Level: developer
662 
663   Note:
664   `TSGetI2Jacobian()` is normally used, but it calls this function internally because the user context is actually
665   associated with the `DM`.
666 
667 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetI2Jacobian()`, `TSGetI2Jacobian()`, `TSI2JacobianFn`
668 @*/
669 PetscErrorCode DMTSGetI2Jacobian(DM dm, TSI2JacobianFn **jac, void **ctx)
670 {
671   DMTS tsdm;
672 
673   PetscFunctionBegin;
674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
683 
684 /*@C
685   DMTSSetRHSFunction - set `TS` explicit residual evaluation function into a `DMTS`
686 
687   Not Collective
688 
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
693 
694   Level: developer
695 
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.
700 
701 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSRHSFunctionFn`
702 @*/
703 PetscErrorCode DMTSSetRHSFunction(DM dm, TSRHSFunctionFn *func, void *ctx)
704 {
705   DMTS tsdm;
706 
707   PetscFunctionBegin;
708   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
721 
722 /*@C
723   DMTSSetRHSFunctionContextDestroy - set `TS` explicit residual evaluation context destroy function into a `DMTS`
724 
725   Not Collective
726 
727   Input Parameters:
728 + dm - `DM` to be used with `TS`
729 - f  - explicit evaluation context destroy function
730 
731   Level: developer
732 
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.
737 
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.
740 
741 .seealso: [](ch_ts), `DMTS`, `TSSetRHSFunctionContextDestroy()`, `DMTSSetRHSFunction()`, `TSSetRHSFunction()`
742 @*/
743 PetscErrorCode DMTSSetRHSFunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *))
744 {
745   DMTS tsdm;
746 
747   PetscFunctionBegin;
748   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
749   PetscCall(DMGetDMTSWrite(dm, &tsdm));
750   if (tsdm->rhsfunctionctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->rhsfunctionctxcontainer, f));
751   PetscFunctionReturn(PETSC_SUCCESS);
752 }
753 
754 PetscErrorCode DMTSUnsetRHSFunctionContext_Internal(DM dm)
755 {
756   DMTS tsdm;
757 
758   PetscFunctionBegin;
759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
760   PetscCall(DMGetDMTSWrite(dm, &tsdm));
761   PetscCall(DMTSUnsetRHSFunctionContext_DMTS(tsdm));
762   tsdm->rhsfunctionctxcontainer = NULL;
763   PetscFunctionReturn(PETSC_SUCCESS);
764 }
765 
766 /*@C
767   DMTSSetTransientVariable - sets function to transform from state to transient variables into a `DMTS`
768 
769   Logically Collective
770 
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
775 
776   Level: developer
777 
778   Notes:
779   Normally `TSSetTransientVariable()` is used
780 
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
786 
787   $$
788   dF/dP + shift * dF/dCdot dC/dP.
789   $$
790 
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;
796 
797   PetscFunctionBegin;
798   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
799   PetscCall(DMGetDMTSWrite(dm, &dmts));
800   dmts->ops->transientvar = tvar;
801   dmts->transientvarctx   = ctx;
802   PetscFunctionReturn(PETSC_SUCCESS);
803 }
804 
805 /*@C
806   DMTSGetTransientVariable - gets function to transform from state to transient variables set with `DMTSSetTransientVariable()` from a `TSDM`
807 
808   Logically Collective
809 
810   Input Parameter:
811 . dm - `DM` to be used with `TS`
812 
813   Output Parameters:
814 + tvar - a function that transforms to transient variables, see `TSTransientVariableFn` for the calling sequence
815 - ctx  - a context for tvar
816 
817   Level: developer
818 
819   Note:
820   Normally `TSSetTransientVariable()` is used
821 
822 .seealso: [](ch_ts), `DMTS`, `DM`, `DMTSSetTransientVariable()`, `DMTSGetIFunction()`, `DMTSGetIJacobian()`, `TSTransientVariableFn`
823 @*/
824 PetscErrorCode DMTSGetTransientVariable(DM dm, TSTransientVariableFn **tvar, void *ctx)
825 {
826   DMTS dmts;
827 
828   PetscFunctionBegin;
829   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
830   PetscCall(DMGetDMTS(dm, &dmts));
831   if (tvar) *tvar = dmts->ops->transientvar;
832   if (ctx) *(void **)ctx = dmts->transientvarctx;
833   PetscFunctionReturn(PETSC_SUCCESS);
834 }
835 
836 /*@C
837   DMTSGetSolutionFunction - gets the `TS` solution evaluation function from a `DMTS`
838 
839   Not Collective
840 
841   Input Parameter:
842 . dm - `DM` to be used with `TS`
843 
844   Output Parameters:
845 + func - solution function evaluation function, for calling sequence see `TSSolutionFn`
846 - ctx  - context for solution evaluation
847 
848   Level: developer
849 
850 .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `DMTSSetSolutionFunction()`, `TSSolutionFn`
851 @*/
852 PetscErrorCode DMTSGetSolutionFunction(DM dm, TSSolutionFn **func, void **ctx)
853 {
854   DMTS tsdm;
855 
856   PetscFunctionBegin;
857   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
858   PetscCall(DMGetDMTS(dm, &tsdm));
859   if (func) *func = tsdm->ops->solution;
860   if (ctx) *ctx = tsdm->solutionctx;
861   PetscFunctionReturn(PETSC_SUCCESS);
862 }
863 
864 /*@C
865   DMTSSetSolutionFunction - set `TS` solution evaluation function into a `DMTS`
866 
867   Not Collective
868 
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
873 
874   Level: developer
875 
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.
880 
881 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSGetSolutionFunction()`, `TSSolutionFn`
882 @*/
883 PetscErrorCode DMTSSetSolutionFunction(DM dm, TSSolutionFn *func, void *ctx)
884 {
885   DMTS tsdm;
886 
887   PetscFunctionBegin;
888   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
889   PetscCall(DMGetDMTSWrite(dm, &tsdm));
890   if (func) tsdm->ops->solution = func;
891   if (ctx) tsdm->solutionctx = ctx;
892   PetscFunctionReturn(PETSC_SUCCESS);
893 }
894 
895 /*@C
896   DMTSSetForcingFunction - set `TS` forcing function evaluation function into a `DMTS`
897 
898   Not Collective
899 
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
904 
905   Level: developer
906 
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.
911 
912 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSForcingFn`, `TSSetForcingFunction()`, `DMTSGetForcingFunction()`
913 @*/
914 PetscErrorCode DMTSSetForcingFunction(DM dm, TSForcingFn *func, void *ctx)
915 {
916   DMTS tsdm;
917 
918   PetscFunctionBegin;
919   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
920   PetscCall(DMGetDMTSWrite(dm, &tsdm));
921   if (func) tsdm->ops->forcing = func;
922   if (ctx) tsdm->forcingctx = ctx;
923   PetscFunctionReturn(PETSC_SUCCESS);
924 }
925 
926 /*@C
927   DMTSGetForcingFunction - get `TS` forcing function evaluation function from a `DMTS`
928 
929   Not Collective
930 
931   Input Parameter:
932 . dm - `DM` to be used with `TS`
933 
934   Output Parameters:
935 + f   - forcing function evaluation function; see `TSForcingFn` for the calling sequence
936 - ctx - context for solution evaluation
937 
938   Level: developer
939 
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.
944 
945 .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSSetForcingFunction()`, `TSForcingFn`
946 @*/
947 PetscErrorCode DMTSGetForcingFunction(DM dm, TSForcingFn **f, void **ctx)
948 {
949   DMTS tsdm;
950 
951   PetscFunctionBegin;
952   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
953   PetscCall(DMGetDMTSWrite(dm, &tsdm));
954   if (f) *f = tsdm->ops->forcing;
955   if (ctx) *ctx = tsdm->forcingctx;
956   PetscFunctionReturn(PETSC_SUCCESS);
957 }
958 
959 /*@C
960   DMTSGetRHSFunction - get `TS` explicit residual evaluation function from a `DMTS`
961 
962   Not Collective
963 
964   Input Parameter:
965 . dm - `DM` to be used with `TS`
966 
967   Output Parameters:
968 + func - residual evaluation function, for calling sequence see `TSRHSFunctionFn`
969 - ctx  - context for residual evaluation
970 
971   Level: developer
972 
973   Note:
974   `TSGetRHSFunction()` is normally used, but it calls this function internally because the user context is actually
975   associated with the DM.
976 
977 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `TSRHSFunctionFn`, `TSGetRHSFunction()`
978 @*/
979 PetscErrorCode DMTSGetRHSFunction(DM dm, TSRHSFunctionFn **func, void **ctx)
980 {
981   DMTS tsdm;
982 
983   PetscFunctionBegin;
984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
993 
994 /*@C
995   DMTSSetIJacobian - set `TS` Jacobian evaluation function into a `DMTS`
996 
997   Not Collective
998 
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
1003 
1004   Level: developer
1005 
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.
1010 
1011 .seealso: [](ch_ts), `DMTS`, `TS`, `DM`, `TSIJacobianFn`, `DMTSGetIJacobian()`, `TSSetIJacobian()`
1012 @*/
1013 PetscErrorCode DMTSSetIJacobian(DM dm, TSIJacobianFn *func, void *ctx)
1014 {
1015   DMTS tsdm;
1016 
1017   PetscFunctionBegin;
1018   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
1031 
1032 /*@C
1033   DMTSSetIJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function into a `DMTS`
1034 
1035   Not Collective
1036 
1037   Input Parameters:
1038 + dm - `DM` to be used with `TS`
1039 - f  - Jacobian evaluation context destroy function
1040 
1041   Level: developer
1042 
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.
1047 
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.
1050 
1051 .seealso: [](ch_ts), `DMTS`, `TSSetIJacobianContextDestroy()`, `TSSetI2JacobianContextDestroy()`, `DMTSSetIJacobian()`, `TSSetIJacobian()`
1052 @*/
1053 PetscErrorCode DMTSSetIJacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
1054 {
1055   DMTS tsdm;
1056 
1057   PetscFunctionBegin;
1058   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1059   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1060   if (tsdm->ijacobianctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->ijacobianctxcontainer, f));
1061   PetscFunctionReturn(PETSC_SUCCESS);
1062 }
1063 
1064 PetscErrorCode DMTSUnsetIJacobianContext_Internal(DM dm)
1065 {
1066   DMTS tsdm;
1067 
1068   PetscFunctionBegin;
1069   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1070   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1071   PetscCall(DMTSUnsetIJacobianContext_DMTS(tsdm));
1072   PetscFunctionReturn(PETSC_SUCCESS);
1073 }
1074 
1075 /*@C
1076   DMTSGetIJacobian - get `TS` Jacobian evaluation function from a `DMTS`
1077 
1078   Not Collective
1079 
1080   Input Parameter:
1081 . dm - `DM` to be used with `TS`
1082 
1083   Output Parameters:
1084 + func - Jacobian evaluation function, for calling sequence see `TSIJacobianFn`
1085 - ctx  - context for residual evaluation
1086 
1087   Level: developer
1088 
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.
1093 
1094 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetIJacobian()`, `TSIJacobianFn`
1095 @*/
1096 PetscErrorCode DMTSGetIJacobian(DM dm, TSIJacobianFn **func, void **ctx)
1097 {
1098   DMTS tsdm;
1099 
1100   PetscFunctionBegin;
1101   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
1110 
1111 /*@C
1112   DMTSSetRHSJacobian - set `TS` Jacobian evaluation function into a `DMTS`
1113 
1114   Not Collective
1115 
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
1120 
1121   Level: developer
1122 
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.
1127 
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.
1130 
1131 .seealso: [](ch_ts), `DMTS`, `TSRHSJacobianFn`, `DMTSGetRHSJacobian()`, `TSSetRHSJacobian()`
1132 @*/
1133 PetscErrorCode DMTSSetRHSJacobian(DM dm, TSRHSJacobianFn *func, void *ctx)
1134 {
1135   DMTS tsdm;
1136 
1137   PetscFunctionBegin;
1138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
1151 
1152 /*@C
1153   DMTSSetRHSJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function from a `DMTS`
1154 
1155   Not Collective
1156 
1157   Input Parameters:
1158 + dm - `DM` to be used with `TS`
1159 - f  - Jacobian evaluation context destroy function
1160 
1161   Level: developer
1162 
1163   Note:
1164   The user usually calls `TSSetRHSJacobianContextDestroy()` which calls this routine
1165 
1166 .seealso: [](ch_ts), `DMTS`, `TS`, `TSSetRHSJacobianContextDestroy()`, `DMTSSetRHSJacobian()`, `TSSetRHSJacobian()`
1167 @*/
1168 PetscErrorCode DMTSSetRHSJacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
1169 {
1170   DMTS tsdm;
1171 
1172   PetscFunctionBegin;
1173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1174   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1175   if (tsdm->rhsjacobianctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->rhsjacobianctxcontainer, f));
1176   PetscFunctionReturn(PETSC_SUCCESS);
1177 }
1178 
1179 PetscErrorCode DMTSUnsetRHSJacobianContext_Internal(DM dm)
1180 {
1181   DMTS tsdm;
1182 
1183   PetscFunctionBegin;
1184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1185   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1186   PetscCall(DMTSUnsetRHSJacobianContext_DMTS(tsdm));
1187   PetscFunctionReturn(PETSC_SUCCESS);
1188 }
1189 
1190 /*@C
1191   DMTSGetRHSJacobian - get `TS` Jacobian evaluation function from a `DMTS`
1192 
1193   Not Collective
1194 
1195   Input Parameter:
1196 . dm - `DM` to be used with `TS`
1197 
1198   Output Parameters:
1199 + func - Jacobian evaluation function, for calling sequence see `TSRHSJacobianFn`
1200 - ctx  - context for residual evaluation
1201 
1202   Level: developer
1203 
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.
1208 
1209 .seealso: [](ch_ts), `DMTS`, `DM`, `TS`, `DMTSSetRHSJacobian()`, `TSRHSJacobianFn`
1210 @*/
1211 PetscErrorCode DMTSGetRHSJacobian(DM dm, TSRHSJacobianFn **func, void **ctx)
1212 {
1213   DMTS tsdm;
1214 
1215   PetscFunctionBegin;
1216   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 }
1225 
1226 /*@C
1227   DMTSSetIFunctionSerialize - sets functions used to view and load a `TSIFunctionFn` context
1228 
1229   Not Collective
1230 
1231   Input Parameters:
1232 + dm   - `DM` to be used with `TS`
1233 . view - viewer function
1234 - load - loading function
1235 
1236   Level: developer
1237 
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;
1243 
1244   PetscFunctionBegin;
1245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1246   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1247   tsdm->ops->ifunctionview = view;
1248   tsdm->ops->ifunctionload = load;
1249   PetscFunctionReturn(PETSC_SUCCESS);
1250 }
1251 
1252 /*@C
1253   DMTSSetIJacobianSerialize - sets functions used to view and load a `TSIJacobianFn` context
1254 
1255   Not Collective
1256 
1257   Input Parameters:
1258 + dm   - `DM` to be used with `TS`
1259 . view - viewer function
1260 - load - loading function
1261 
1262   Level: developer
1263 
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;
1269 
1270   PetscFunctionBegin;
1271   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1272   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1273   tsdm->ops->ijacobianview = view;
1274   tsdm->ops->ijacobianload = load;
1275   PetscFunctionReturn(PETSC_SUCCESS);
1276 }
1277