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:   PetscObjectCompose((PetscObject)tsdm, "rhs function ctx", NULL);
  7:   tsdm->rhsfunctionctxcontainer = NULL;
  8:   return 0;
  9: }

 11: static PetscErrorCode DMTSUnsetRHSJacobianContext_DMTS(DMTS tsdm)
 12: {
 13:   PetscObjectCompose((PetscObject)tsdm, "rhs jacobian ctx", NULL);
 14:   tsdm->rhsjacobianctxcontainer = NULL;
 15:   return 0;
 16: }

 18: static PetscErrorCode DMTSUnsetIFunctionContext_DMTS(DMTS tsdm)
 19: {
 20:   PetscObjectCompose((PetscObject)tsdm, "ifunction ctx", NULL);
 21:   tsdm->ifunctionctxcontainer = NULL;
 22:   return 0;
 23: }

 25: static PetscErrorCode DMTSUnsetIJacobianContext_DMTS(DMTS tsdm)
 26: {
 27:   PetscObjectCompose((PetscObject)tsdm, "ijacobian ctx", NULL);
 28:   tsdm->ijacobianctxcontainer = NULL;
 29:   return 0;
 30: }

 32: static PetscErrorCode DMTSUnsetI2FunctionContext_DMTS(DMTS tsdm)
 33: {
 34:   PetscObjectCompose((PetscObject)tsdm, "i2function ctx", NULL);
 35:   tsdm->i2functionctxcontainer = NULL;
 36:   return 0;
 37: }

 39: static PetscErrorCode DMTSUnsetI2JacobianContext_DMTS(DMTS tsdm)
 40: {
 41:   PetscObjectCompose((PetscObject)tsdm, "i2jacobian ctx", NULL);
 42:   tsdm->i2jacobianctxcontainer = NULL;
 43:   return 0;
 44: }

 46: static PetscErrorCode DMTSDestroy(DMTS *kdm)
 47: {
 48:   if (!*kdm) return 0;
 50:   if (--((PetscObject)(*kdm))->refct > 0) {
 51:     *kdm = NULL;
 52:     return 0;
 53:   }
 54:   DMTSUnsetRHSFunctionContext_DMTS(*kdm);
 55:   DMTSUnsetRHSJacobianContext_DMTS(*kdm);
 56:   DMTSUnsetIFunctionContext_DMTS(*kdm);
 57:   DMTSUnsetIJacobianContext_DMTS(*kdm);
 58:   DMTSUnsetI2FunctionContext_DMTS(*kdm);
 59:   DMTSUnsetI2JacobianContext_DMTS(*kdm);
 60:   PetscTryTypeMethod(*kdm, destroy);
 61:   PetscHeaderDestroy(kdm);
 62:   return 0;
 63: }

 65: PetscErrorCode DMTSLoad(DMTS kdm, PetscViewer viewer)
 66: {
 67:   PetscViewerBinaryRead(viewer, &kdm->ops->ifunction, 1, NULL, PETSC_FUNCTION);
 68:   PetscViewerBinaryRead(viewer, &kdm->ops->ifunctionview, 1, NULL, PETSC_FUNCTION);
 69:   PetscViewerBinaryRead(viewer, &kdm->ops->ifunctionload, 1, NULL, PETSC_FUNCTION);
 70:   if (kdm->ops->ifunctionload) {
 71:     void *ctx;

 73:     PetscContainerGetPointer(kdm->ifunctionctxcontainer, &ctx);
 74:     (*kdm->ops->ifunctionload)(&ctx, viewer);
 75:   }
 76:   PetscViewerBinaryRead(viewer, &kdm->ops->ijacobian, 1, NULL, PETSC_FUNCTION);
 77:   PetscViewerBinaryRead(viewer, &kdm->ops->ijacobianview, 1, NULL, PETSC_FUNCTION);
 78:   PetscViewerBinaryRead(viewer, &kdm->ops->ijacobianload, 1, NULL, PETSC_FUNCTION);
 79:   if (kdm->ops->ijacobianload) {
 80:     void *ctx;

 82:     PetscContainerGetPointer(kdm->ijacobianctxcontainer, &ctx);
 83:     (*kdm->ops->ijacobianload)(&ctx, viewer);
 84:   }
 85:   return 0;
 86: }

 88: PetscErrorCode DMTSView(DMTS kdm, PetscViewer viewer)
 89: {
 90:   PetscBool isascii, isbinary;

 92:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii);
 93:   PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary);
 94:   if (isascii) {
 95: #if defined(PETSC_SERIALIZE_FUNCTIONS)
 96:     const char *fname;

 98:     PetscFPTFind(kdm->ops->ifunction, &fname);
 99:     if (fname) PetscViewerASCIIPrintf(viewer, "  IFunction used by TS: %s\n", fname);
100:     PetscFPTFind(kdm->ops->ijacobian, &fname);
101:     if (fname) PetscViewerASCIIPrintf(viewer, "  IJacobian function used by TS: %s\n", fname);
102: #endif
103:   } else if (isbinary) {
104:     struct {
105:       TSIFunction ifunction;
106:     } funcstruct;
107:     struct {
108:       PetscErrorCode (*ifunctionview)(void *, PetscViewer);
109:     } funcviewstruct;
110:     struct {
111:       PetscErrorCode (*ifunctionload)(void **, PetscViewer);
112:     } funcloadstruct;
113:     struct {
114:       TSIJacobian ijacobian;
115:     } jacstruct;
116:     struct {
117:       PetscErrorCode (*ijacobianview)(void *, PetscViewer);
118:     } jacviewstruct;
119:     struct {
120:       PetscErrorCode (*ijacobianload)(void **, PetscViewer);
121:     } jacloadstruct;

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

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

144:       PetscContainerGetPointer(kdm->ijacobianctxcontainer, &ctx);
145:       (*kdm->ops->ijacobianview)(ctx, viewer);
146:     }
147:   }
148:   return 0;
149: }

151: static PetscErrorCode DMTSCreate(MPI_Comm comm, DMTS *kdm)
152: {
153:   TSInitializePackage();
154:   PetscHeaderCreate(*kdm, DMTS_CLASSID, "DMTS", "DMTS", "DMTS", comm, DMTSDestroy, DMTSView);
155:   return 0;
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, void *ctx)
162: {
163:   DMCopyDMTS(dm, dmc);
164:   return 0;
165: }

167: /* This could restrict auxiliary information to the coarse level.
168:  */
169: static PetscErrorCode DMRestrictHook_DMTS(DM dm, Mat Restrict, Vec rscale, Mat Inject, DM dmc, void *ctx)
170: {
171:   return 0;
172: }

174: static PetscErrorCode DMSubDomainHook_DMTS(DM dm, DM subdm, void *ctx)
175: {
176:   DMCopyDMTS(dm, subdm);
177:   return 0;
178: }

180: /* This could restrict auxiliary information to the coarse level.
181:  */
182: static PetscErrorCode DMSubDomainRestrictHook_DMTS(DM dm, VecScatter gscat, VecScatter lscat, DM subdm, void *ctx)
183: {
184:   return 0;
185: }

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

190:    Not Collective

192:    Input Parameters:
193: +  kdm - Original `DMTS`
194: -  nkdm - `DMTS` to receive the data, should have been created with `DMTSCreate()`

196:    Level: developer

198: .seealso: [](chapter_ts), `DMTSCreate()`, `DMTSDestroy()`
199: @*/
200: PetscErrorCode DMTSCopy(DMTS kdm, DMTS nkdm)
201: {
204:   nkdm->ops->rhsfunction = kdm->ops->rhsfunction;
205:   nkdm->ops->rhsjacobian = kdm->ops->rhsjacobian;
206:   nkdm->ops->ifunction   = kdm->ops->ifunction;
207:   nkdm->ops->ijacobian   = kdm->ops->ijacobian;
208:   nkdm->ops->i2function  = kdm->ops->i2function;
209:   nkdm->ops->i2jacobian  = kdm->ops->i2jacobian;
210:   nkdm->ops->solution    = kdm->ops->solution;
211:   nkdm->ops->destroy     = kdm->ops->destroy;
212:   nkdm->ops->duplicate   = kdm->ops->duplicate;

214:   nkdm->solutionctx             = kdm->solutionctx;
215:   nkdm->rhsfunctionctxcontainer = kdm->rhsfunctionctxcontainer;
216:   nkdm->rhsjacobianctxcontainer = kdm->rhsjacobianctxcontainer;
217:   nkdm->ifunctionctxcontainer   = kdm->ifunctionctxcontainer;
218:   nkdm->ijacobianctxcontainer   = kdm->ijacobianctxcontainer;
219:   nkdm->i2functionctxcontainer  = kdm->i2functionctxcontainer;
220:   nkdm->i2jacobianctxcontainer  = kdm->i2jacobianctxcontainer;
221:   if (nkdm->rhsfunctionctxcontainer) PetscObjectCompose((PetscObject)nkdm, "rhs function ctx", (PetscObject)nkdm->rhsfunctionctxcontainer);
222:   if (nkdm->rhsjacobianctxcontainer) PetscObjectCompose((PetscObject)nkdm, "rhs jacobian ctx", (PetscObject)nkdm->rhsjacobianctxcontainer);
223:   if (nkdm->ifunctionctxcontainer) PetscObjectCompose((PetscObject)nkdm, "ifunction ctx", (PetscObject)nkdm->ifunctionctxcontainer);
224:   if (nkdm->ijacobianctxcontainer) PetscObjectCompose((PetscObject)nkdm, "ijacobian ctx", (PetscObject)nkdm->ijacobianctxcontainer);
225:   if (nkdm->i2functionctxcontainer) PetscObjectCompose((PetscObject)nkdm, "i2function ctx", (PetscObject)nkdm->i2functionctxcontainer);
226:   if (nkdm->i2jacobianctxcontainer) PetscObjectCompose((PetscObject)nkdm, "i2jacobian ctx", (PetscObject)nkdm->i2jacobianctxcontainer);

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

230:   /*
231:   nkdm->fortran_func_pointers[0] = kdm->fortran_func_pointers[0];
232:   nkdm->fortran_func_pointers[1] = kdm->fortran_func_pointers[1];
233:   nkdm->fortran_func_pointers[2] = kdm->fortran_func_pointers[2];
234:   */

236:   /* implementation specific copy hooks */
237:   PetscTryTypeMethod(kdm, duplicate, nkdm);
238:   return 0;
239: }

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

244:    Not Collective

246:    Input Parameter:
247: .  dm - `DM` to be used with `TS`

249:    Output Parameter:
250: .  tsdm - private `DMTS` context

252:    Level: developer

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

257: .seealso: [](chapter_ts), `DMTS`, `DMGetDMTSWrite()`
258: @*/
259: PetscErrorCode DMGetDMTS(DM dm, DMTS *tsdm)
260: {
262:   *tsdm = (DMTS)dm->dmts;
263:   if (!*tsdm) {
264:     PetscInfo(dm, "Creating new DMTS\n");
265:     DMTSCreate(PetscObjectComm((PetscObject)dm), tsdm);
266:     dm->dmts            = (PetscObject)*tsdm;
267:     (*tsdm)->originaldm = dm;
268:     DMCoarsenHookAdd(dm, DMCoarsenHook_DMTS, DMRestrictHook_DMTS, NULL);
269:     DMSubDomainHookAdd(dm, DMSubDomainHook_DMTS, DMSubDomainRestrictHook_DMTS, NULL);
270:   }
271:   return 0;
272: }

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

277:    Not Collective

279:    Input Parameter:
280: .  dm - `DM` to be used with `TS`

282:    Output Parameter:
283: .  tsdm - private `DMTS` context

285:    Level: developer

287: .seealso: [](chapter_ts), `DMTS`, `DMGetDMTS()`
288: @*/
289: PetscErrorCode DMGetDMTSWrite(DM dm, DMTS *tsdm)
290: {
291:   DMTS sdm;

294:   DMGetDMTS(dm, &sdm);
296:   if (sdm->originaldm != dm) { /* Copy on write */
297:     DMTS oldsdm = sdm;
298:     PetscInfo(dm, "Copying DMTS due to write\n");
299:     DMTSCreate(PetscObjectComm((PetscObject)dm), &sdm);
300:     DMTSCopy(oldsdm, sdm);
301:     DMTSDestroy((DMTS *)&dm->dmts);
302:     dm->dmts        = (PetscObject)sdm;
303:     sdm->originaldm = dm;
304:   }
305:   *tsdm = sdm;
306:   return 0;
307: }

309: /*@C
310:    DMCopyDMTS - copies a `DM` context to a new `DM`

312:    Logically Collective

314:    Input Parameters:
315: +  dmsrc - `DM` to obtain context from
316: -  dmdest - `DM` to add context to

318:    Level: developer

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

323: .seealso: [](chapter_ts), `DMTS`, `DMGetDMTS()`, `TSSetDM()`
324: @*/
325: PetscErrorCode DMCopyDMTS(DM dmsrc, DM dmdest)
326: {
329:   DMTSDestroy((DMTS *)&dmdest->dmts);
330:   dmdest->dmts = dmsrc->dmts;
331:   PetscObjectReference(dmdest->dmts);
332:   DMCoarsenHookAdd(dmdest, DMCoarsenHook_DMTS, DMRestrictHook_DMTS, NULL);
333:   DMSubDomainHookAdd(dmdest, DMSubDomainHook_DMTS, DMSubDomainRestrictHook_DMTS, NULL);
334:   return 0;
335: }

337: /*@C
338:    DMTSSetIFunction - set `TS` implicit function evaluation function

340:    Not Collective

342:    Input Parameters:
343: +  dm - `DM` to be used with `TS`
344: .  func - function evaluating f(t,u,u_t)
345: -  ctx - context for residual evaluation

347:    Calling sequence of func:
348: $     PetscErrorCode func(TS ts,PetscReal t,Vec u,Vec u_t,Vec F,ctx);

350: +  t   - time at step/stage being solved
351: .  u   - state vector
352: .  u_t - time derivative of state vector
353: .  F   - function vector
354: -  ctx - [optional] user-defined context for matrix evaluation routine

356:    Level: advanced

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

363: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `TSSetIFunction()`, `DMTSSetJacobian()`
364: @*/
365: PetscErrorCode DMTSSetIFunction(DM dm, TSIFunction func, void *ctx)
366: {
367:   DMTS tsdm;

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

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

386:    Not Collective

388:    Input Parameters:
389: +  dm - `DM` to be used with `TS`
390: -  f - implicit evaluation context destroy function

392:    Level: advanced

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

401:   DMGetDMTSWrite(dm, &tsdm);
402:   if (tsdm->ifunctionctxcontainer) PetscContainerSetUserDestroy(tsdm->ifunctionctxcontainer, f);
403:   return 0;
404: }

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

411:   DMGetDMTSWrite(dm, &tsdm);
412:   DMTSUnsetIFunctionContext_DMTS(tsdm);
413:   return 0;
414: }

416: /*@C
417:    DMTSGetIFunction - get `TS` implicit residual evaluation function

419:    Not Collective

421:    Input Parameter:
422: .  dm - `DM` to be used with `TS`

424:    Output Parameters:
425: +  func - function evaluation function, see `TSSetIFunction()` for calling sequence
426: -  ctx - context for residual evaluation

428:    Level: advanced

430:    Note:
431:    `TSGetFunction()` is normally used, but it calls this function internally because the user context is actually
432:    associated with the `DM`.

434: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `DMTSSetFunction()`, `TSSetFunction()`
435: @*/
436: PetscErrorCode DMTSGetIFunction(DM dm, TSIFunction *func, void **ctx)
437: {
438:   DMTS tsdm;

441:   DMGetDMTS(dm, &tsdm);
442:   if (func) *func = tsdm->ops->ifunction;
443:   if (ctx) {
444:     if (tsdm->ifunctionctxcontainer) PetscContainerGetPointer(tsdm->ifunctionctxcontainer, ctx);
445:     else *ctx = NULL;
446:   }
447:   return 0;
448: }

450: /*@C
451:    DMTSSetI2Function - set `TS` implicit function evaluation function for 2nd order systems

453:    Not Collective

455:    Input Parameters:
456: +  dm - `DM` to be used with `TS`
457: .  fun - function evaluation routine
458: -  ctx - context for residual evaluation

460:    Calling sequence of fun:
461: $     PetscErrorCode fun(TS ts,PetscReal t,Vec U,Vec U_t,Vec U_tt,Vec F,ctx);

463: +  t    - time at step/stage being solved
464: .  U    - state vector
465: .  U_t  - time derivative of state vector
466: .  U_tt - second time derivative of state vector
467: .  F    - function vector
468: -  ctx  - [optional] user-defined context for matrix evaluation routine (may be NULL)

470:    Level: advanced

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

476: .seealso: [](chapter_ts), `DM`, `TS`, `TSSetI2Function()`
477: @*/
478: PetscErrorCode DMTSSetI2Function(DM dm, TSI2Function fun, void *ctx)
479: {
480:   DMTS tsdm;

483:   DMGetDMTSWrite(dm, &tsdm);
484:   if (fun) tsdm->ops->i2function = fun;
485:   if (ctx) {
486:     PetscContainer ctxcontainer;
487:     PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer);
488:     PetscContainerSetPointer(ctxcontainer, ctx);
489:     PetscObjectCompose((PetscObject)tsdm, "i2function ctx", (PetscObject)ctxcontainer);
490:     tsdm->i2functionctxcontainer = ctxcontainer;
491:     PetscContainerDestroy(&ctxcontainer);
492:   }
493:   return 0;
494: }

496: /*@C
497:    DMTSSetI2FunctionContextDestroy - set `TS` implicit evaluation for 2nd order systems context destroy

499:    Not Collective

501:    Input Parameters:
502: +  dm - `DM` to be used with `TS`
503: -  f - implicit evaluation context destroy function

505:    Level: advanced

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

511: .seealso: [](chapter_ts), `TSSetI2FunctionContextDestroy()`, `DMTSSetI2Function()`, `TSSetI2Function()`
512: @*/
513: PetscErrorCode DMTSSetI2FunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *))
514: {
515:   DMTS tsdm;

518:   DMGetDMTSWrite(dm, &tsdm);
519:   if (tsdm->i2functionctxcontainer) PetscContainerSetUserDestroy(tsdm->i2functionctxcontainer, f);
520:   return 0;
521: }

523: PetscErrorCode DMTSUnsetI2FunctionContext_Internal(DM dm)
524: {
525:   DMTS tsdm;

528:   DMGetDMTSWrite(dm, &tsdm);
529:   DMTSUnsetI2FunctionContext_DMTS(tsdm);
530:   return 0;
531: }

533: /*@C
534:    DMTSGetI2Function - get `TS` implicit residual evaluation function for 2nd order systems

536:    Not Collective

538:    Input Parameter:
539: .  dm - `DM` to be used with `TS`

541:    Output Parameters:
542: +  fun - function evaluation function, see `TSSetI2Function()` for calling sequence
543: -  ctx - context for residual evaluation

545:    Level: advanced

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

551: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetI2Function()`, `TSGetI2Function()`
552: @*/
553: PetscErrorCode DMTSGetI2Function(DM dm, TSI2Function *fun, void **ctx)
554: {
555:   DMTS tsdm;

558:   DMGetDMTS(dm, &tsdm);
559:   if (fun) *fun = tsdm->ops->i2function;
560:   if (ctx) {
561:     if (tsdm->i2functionctxcontainer) PetscContainerGetPointer(tsdm->i2functionctxcontainer, ctx);
562:     else *ctx = NULL;
563:   }
564:   return 0;
565: }

567: /*@C
568:    DMTSSetI2Jacobian - set `TS` implicit Jacobian evaluation function for 2nd order systems

570:    Not Collective

572:    Input Parameters:
573: +  dm - `DM` to be used with `TS`
574: .  fun - Jacobian evaluation routine
575: -  ctx - context for Jacobian evaluation

577:    Calling sequence of jac:
578: $    PetscErrorCode jac(TS ts,PetscReal t,Vec U,Vec U_t,Vec U_tt,PetscReal v,PetscReal a,Mat J,Mat P,void *ctx);

580: +  t    - time at step/stage being solved
581: .  U    - state vector
582: .  U_t  - time derivative of state vector
583: .  U_tt - second time derivative of state vector
584: .  v    - shift for U_t
585: .  a    - shift for U_tt
586: .  J    - Jacobian of G(U) = F(t,U,W+v*U,W'+a*U), equivalent to dF/dU + v*dF/dU_t  + a*dF/dU_tt
587: .  P    - preconditioning matrix for J, may be same as J
588: -  ctx  - [optional] user-defined context for matrix evaluation routine

590:    Level: advanced

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

596: .seealso: [](chapter_ts), `DM`, `TS`, `TSSetI2Jacobian()`
597: @*/
598: PetscErrorCode DMTSSetI2Jacobian(DM dm, TSI2Jacobian jac, void *ctx)
599: {
600:   DMTS tsdm;

603:   DMGetDMTSWrite(dm, &tsdm);
604:   if (jac) tsdm->ops->i2jacobian = jac;
605:   if (ctx) {
606:     PetscContainer ctxcontainer;
607:     PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer);
608:     PetscContainerSetPointer(ctxcontainer, ctx);
609:     PetscObjectCompose((PetscObject)tsdm, "i2jacobian ctx", (PetscObject)ctxcontainer);
610:     tsdm->i2jacobianctxcontainer = ctxcontainer;
611:     PetscContainerDestroy(&ctxcontainer);
612:   }
613:   return 0;
614: }

616: /*@C
617:    DMTSSetI2JacobianContextDestroy - set `TS` implicit Jacobian evaluation for 2nd order systems context destroy function

619:    Not Collective

621:    Input Parameters:
622: +  dm - `DM` to be used with `TS`
623: -  f - implicit Jacobian evaluation context destroy function

625:    Level: advanced

627: .seealso: [](chapter_ts), `DM`, `TS`, `TSSetI2JacobianContextDestroy()`, `DMTSSetI2Jacobian()`, `TSSetI2Jacobian()`
628: @*/
629: PetscErrorCode DMTSSetI2JacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
630: {
631:   DMTS tsdm;

634:   DMGetDMTSWrite(dm, &tsdm);
635:   if (tsdm->i2jacobianctxcontainer) PetscContainerSetUserDestroy(tsdm->i2jacobianctxcontainer, f);
636:   return 0;
637: }

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

644:   DMGetDMTSWrite(dm, &tsdm);
645:   DMTSUnsetI2JacobianContext_DMTS(tsdm);
646:   return 0;
647: }

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

652:    Not Collective

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

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

661:    Level: advanced

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

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

674:   DMGetDMTS(dm, &tsdm);
675:   if (jac) *jac = tsdm->ops->i2jacobian;
676:   if (ctx) {
677:     if (tsdm->i2jacobianctxcontainer) PetscContainerGetPointer(tsdm->i2jacobianctxcontainer, ctx);
678:     else *ctx = NULL;
679:   }
680:   return 0;
681: }

683: /*@C
684:    DMTSSetRHSFunction - set `TS` explicit residual evaluation function

686:    Not Collective

688:    Input Parameters:
689: +  dm - `DM` to be used with `TS`
690: .  func - RHS function evaluation routine
691: -  ctx - context for residual evaluation

693:     Calling sequence of func:
694: $     PetscErrorCode func(TS ts,PetscReal t,Vec u,Vec F,void *ctx);

696: +   ts - timestep context
697: .   t - current timestep
698: .   u - input vector
699: .   F - function vector
700: -   ctx - [optional] user-defined function context

702:    Level: advanced

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

709: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetRHSFunction()`, `DMTSSetJacobian()`
710: @*/
711: PetscErrorCode DMTSSetRHSFunction(DM dm, TSRHSFunction func, void *ctx)
712: {
713:   DMTS tsdm;

716:   DMGetDMTSWrite(dm, &tsdm);
717:   if (func) tsdm->ops->rhsfunction = func;
718:   if (ctx) {
719:     PetscContainer ctxcontainer;
720:     PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer);
721:     PetscContainerSetPointer(ctxcontainer, ctx);
722:     PetscObjectCompose((PetscObject)tsdm, "rhs function ctx", (PetscObject)ctxcontainer);
723:     tsdm->rhsfunctionctxcontainer = ctxcontainer;
724:     PetscContainerDestroy(&ctxcontainer);
725:   }
726:   return 0;
727: }

729: /*@C
730:    DMTSSetRHSFunctionContextDestroy - set `TS` explicit residual evaluation context destroy function

732:    Not Collective

734:    Input Parameters:
735: +  dm - `DM` to be used with `TS`
736: -  f - explicit evaluation context destroy function

738:    Level: advanced

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

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

748: .seealso: [](chapter_ts), `TSSetRHSFunctionContextDestroy()`, `DMTSSetRHSFunction()`, `TSSetRHSFunction()`
749: @*/
750: PetscErrorCode DMTSSetRHSFunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *))
751: {
752:   DMTS tsdm;

755:   DMGetDMTSWrite(dm, &tsdm);
756:   if (tsdm->rhsfunctionctxcontainer) PetscContainerSetUserDestroy(tsdm->rhsfunctionctxcontainer, f);
757:   return 0;
758: }

760: PetscErrorCode DMTSUnsetRHSFunctionContext_Internal(DM dm)
761: {
762:   DMTS tsdm;

765:   DMGetDMTSWrite(dm, &tsdm);
766:   DMTSUnsetRHSFunctionContext_DMTS(tsdm);
767:   tsdm->rhsfunctionctxcontainer = NULL;
768:   return 0;
769: }

771: /*@C
772:    DMTSSetTransientVariable - sets function to transform from state to transient variables

774:    Logically Collective

776:    Input Parameters:
777: +  dm - `DM` to be used with `TS`
778: .  tvar - a function that transforms to transient variables
779: -  ctx - a context for tvar

781:     Calling sequence of tvar:
782: $     PetscErrorCode tvar(TS ts,Vec p,Vec c,void *ctx);

784: +   ts - timestep context
785: .   p - input vector (primitive form)
786: .   c - output vector, transient variables (conservative form)
787: -   ctx - [optional] user-defined function context

789:    Level: advanced

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

798:      dF/dP + shift * dF/dCdot dC/dP.

800: .seealso: [](chapter_ts), `TS`, `TSBDF`, `TSSetTransientVariable()`, `DMTSGetTransientVariable()`, `DMTSSetIFunction()`, `DMTSSetIJacobian()`
801: @*/
802: PetscErrorCode DMTSSetTransientVariable(DM dm, TSTransientVariable tvar, void *ctx)
803: {
804:   DMTS dmts;

807:   DMGetDMTSWrite(dm, &dmts);
808:   dmts->ops->transientvar = tvar;
809:   dmts->transientvarctx   = ctx;
810:   return 0;
811: }

813: /*@C
814:    DMTSGetTransientVariable - gets function to transform from state to transient variables set with `DMTSSetTransientVariable()`

816:    Logically Collective

818:    Input Parameter:
819: .  dm - `DM` to be used with `TS`

821:    Output Parameters:
822: +  tvar - a function that transforms to transient variables
823: -  ctx - a context for tvar

825:    Level: advanced

827: .seealso: [](chapter_ts), `DM`, `DMTSSetTransientVariable()`, `DMTSGetIFunction()`, `DMTSGetIJacobian()`
828: @*/
829: PetscErrorCode DMTSGetTransientVariable(DM dm, TSTransientVariable *tvar, void *ctx)
830: {
831:   DMTS dmts;

834:   DMGetDMTS(dm, &dmts);
835:   if (tvar) *tvar = dmts->ops->transientvar;
836:   if (ctx) *(void **)ctx = dmts->transientvarctx;
837:   return 0;
838: }

840: /*@C
841:    DMTSGetSolutionFunction - gets the `TS` solution evaluation function

843:    Not Collective

845:    Input Parameter:
846: .  dm - `DM` to be used with `TS`

848:    Output Parameters:
849: +  func - solution function evaluation function, see `TSSetSolution()` for calling sequence
850: -  ctx - context for solution evaluation

852:    Level: advanced

854: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`, `DMTSSetSolutionFunction()`
855: @*/
856: PetscErrorCode DMTSGetSolutionFunction(DM dm, TSSolutionFunction *func, void **ctx)
857: {
858:   DMTS tsdm;

861:   DMGetDMTS(dm, &tsdm);
862:   if (func) *func = tsdm->ops->solution;
863:   if (ctx) *ctx = tsdm->solutionctx;
864:   return 0;
865: }

867: /*@C
868:    DMTSSetSolutionFunction - set `TS` solution evaluation function

870:    Not Collective

872:    Input Parameters:
873: +  dm - `DM` to be used with `TS`
874: .  func - solution function evaluation routine
875: -  ctx - context for solution evaluation

877:     Calling sequence of f:
878: $     PetscErrorCode f(TS ts,PetscReal t,Vec u,void *ctx);

880: +   ts - timestep context
881: .   t - current timestep
882: .   u - output vector
883: -   ctx - [optional] user-defined function context

885:    Level: advanced

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

892: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`, `DMTSGetSolutionFunction()`
893: @*/
894: PetscErrorCode DMTSSetSolutionFunction(DM dm, TSSolutionFunction func, void *ctx)
895: {
896:   DMTS tsdm;

899:   DMGetDMTSWrite(dm, &tsdm);
900:   if (func) tsdm->ops->solution = func;
901:   if (ctx) tsdm->solutionctx = ctx;
902:   return 0;
903: }

905: /*@C
906:    DMTSSetForcingFunction - set `TS` forcing function evaluation function

908:    Not Collective

910:    Input Parameters:
911: +  dm - `DM` to be used with `TS`
912: .  f - forcing function evaluation routine
913: -  ctx - context for solution evaluation

915:     Calling sequence of func:
916: $     PetscErrorCode func (TS ts,PetscReal t,Vec f,void *ctx);

918: +   ts - timestep context
919: .   t - current timestep
920: .   f - output vector
921: -   ctx - [optional] user-defined function context

923:    Level: advanced

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

930: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`, `TSSetForcingFunction()`, `DMTSGetForcingFunction()`
931: @*/
932: PetscErrorCode DMTSSetForcingFunction(DM dm, TSForcingFunction f, void *ctx)
933: {
934:   DMTS tsdm;

937:   DMGetDMTSWrite(dm, &tsdm);
938:   if (f) tsdm->ops->forcing = f;
939:   if (ctx) tsdm->forcingctx = ctx;
940:   return 0;
941: }

943: /*@C
944:    DMTSGetForcingFunction - get `TS` forcing function evaluation function

946:    Not Collective

948:    Input Parameter:
949: .   dm - `DM` to be used with `TS`

951:    Output Parameters:
952: +  f - forcing function evaluation function; see `TSForcingFunction` for details
953: -  ctx - context for solution evaluation

955:    Level: advanced

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

962: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`, `TSSetForcingFunction()`, `DMTSGetForcingFunction()`
963: @*/
964: PetscErrorCode DMTSGetForcingFunction(DM dm, TSForcingFunction *f, void **ctx)
965: {
966:   DMTS tsdm;

969:   DMGetDMTSWrite(dm, &tsdm);
970:   if (f) *f = tsdm->ops->forcing;
971:   if (ctx) *ctx = tsdm->forcingctx;
972:   return 0;
973: }

975: /*@C
976:    DMTSGetRHSFunction - get `TS` explicit residual evaluation function

978:    Not Collective

980:    Input Parameter:
981: .  dm - `DM` to be used with `TS`

983:    Output Parameters:
984: +  func - residual evaluation function, see `TSSetRHSFunction()` for calling sequence
985: -  ctx - context for residual evaluation

987:    Level: advanced

989:    Note:
990:    `TSGetFunction()` is normally used, but it calls this function internally because the user context is actually
991:    associated with the DM.

993: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `DMTSSetRHSFunction()`, `TSSetRHSFunction()`
994: @*/
995: PetscErrorCode DMTSGetRHSFunction(DM dm, TSRHSFunction *func, void **ctx)
996: {
997:   DMTS tsdm;

1000:   DMGetDMTS(dm, &tsdm);
1001:   if (func) *func = tsdm->ops->rhsfunction;
1002:   if (ctx) {
1003:     if (tsdm->rhsfunctionctxcontainer) PetscContainerGetPointer(tsdm->rhsfunctionctxcontainer, ctx);
1004:     else *ctx = NULL;
1005:   }
1006:   return 0;
1007: }

1009: /*@C
1010:    DMTSSetIJacobian - set `TS` Jacobian evaluation function

1012:    Not Collective

1014:    Input Parameters:
1015: +  dm - `DM` to be used with `TS`
1016: .  func - Jacobian evaluation routine
1017: -  ctx - context for residual evaluation

1019:    Calling sequence of f:
1020: $    PetscErrorCode f(TS ts,PetscReal t,Vec U,Vec U_t,PetscReal a,Mat Amat,Mat Pmat,void *ctx);

1022: +  t    - time at step/stage being solved
1023: .  U    - state vector
1024: .  U_t  - time derivative of state vector
1025: .  a    - shift
1026: .  Amat - (approximate) Jacobian of F(t,U,W+a*U), equivalent to dF/dU + a*dF/dU_t
1027: .  Pmat - matrix used for constructing preconditioner, usually the same as Amat
1028: -  ctx  - [optional] user-defined context for matrix evaluation routine

1030:    Level: advanced

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

1037: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `TSSetRHSFunction()`, `DMTSGetJacobian()`, `TSSetIJacobian()`, `TSSetIFunction()`
1038: @*/
1039: PetscErrorCode DMTSSetIJacobian(DM dm, TSIJacobian func, void *ctx)
1040: {
1041:   DMTS tsdm;

1044:   DMGetDMTSWrite(dm, &tsdm);
1045:   if (func) tsdm->ops->ijacobian = func;
1046:   if (ctx) {
1047:     PetscContainer ctxcontainer;
1048:     PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer);
1049:     PetscContainerSetPointer(ctxcontainer, ctx);
1050:     PetscObjectCompose((PetscObject)tsdm, "ijacobian ctx", (PetscObject)ctxcontainer);
1051:     tsdm->ijacobianctxcontainer = ctxcontainer;
1052:     PetscContainerDestroy(&ctxcontainer);
1053:   }
1054:   return 0;
1055: }

1057: /*@C
1058:    DMTSSetIJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function

1060:    Not Collective

1062:    Input Parameters:
1063: +  dm - `DM` to be used with `TS`
1064: -  f - Jacobian evaluation context destroy function

1066:    Level: advanced

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

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

1076: .seealso: [](chapter_ts), `TSSetIJacobianContextDestroy()`, `TSSetI2JacobianContextDestroy()`, `DMTSSetIJacobian()`, `TSSetIJacobian()`
1077: @*/
1078: PetscErrorCode DMTSSetIJacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
1079: {
1080:   DMTS tsdm;

1083:   DMGetDMTSWrite(dm, &tsdm);
1084:   if (tsdm->ijacobianctxcontainer) PetscContainerSetUserDestroy(tsdm->ijacobianctxcontainer, f);
1085:   return 0;
1086: }

1088: PetscErrorCode DMTSUnsetIJacobianContext_Internal(DM dm)
1089: {
1090:   DMTS tsdm;

1093:   DMGetDMTSWrite(dm, &tsdm);
1094:   DMTSUnsetIJacobianContext_DMTS(tsdm);
1095:   return 0;
1096: }

1098: /*@C
1099:    DMTSGetIJacobian - get `TS` Jacobian evaluation function

1101:    Not Collective

1103:    Input Parameter:
1104: .  dm - `DM` to be used with `TS`

1106:    Output Parameters:
1107: +  func - Jacobian evaluation function, see `TSSetIJacobian()` for calling sequence
1108: -  ctx - context for residual evaluation

1110:    Level: advanced

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

1117: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`
1118: @*/
1119: PetscErrorCode DMTSGetIJacobian(DM dm, TSIJacobian *func, void **ctx)
1120: {
1121:   DMTS tsdm;

1124:   DMGetDMTS(dm, &tsdm);
1125:   if (func) *func = tsdm->ops->ijacobian;
1126:   if (ctx) {
1127:     if (tsdm->ijacobianctxcontainer) PetscContainerGetPointer(tsdm->ijacobianctxcontainer, ctx);
1128:     else *ctx = NULL;
1129:   }
1130:   return 0;
1131: }

1133: /*@C
1134:    DMTSSetRHSJacobian - set `TS` Jacobian evaluation function

1136:    Not Collective

1138:    Input Parameters:
1139: +  dm - `DM` to be used with `TS`
1140: .  func - Jacobian evaluation routine
1141: -  ctx - context for residual evaluation

1143:    Calling sequence of func:
1144: $     PetscErrorCode func(TS ts,PetscReal t,Vec u,Mat A,Mat B,void *ctx);

1146: +  t - current timestep
1147: .  u - input vector
1148: .  Amat - (approximate) Jacobian matrix
1149: .  Pmat - matrix from which preconditioner is to be constructed (usually the same as Amat)
1150: -  ctx - [optional] user-defined context for matrix evaluation routine

1152:    Level: advanced

1154:    Note:
1155:    `TSSetJacobian()` is normally used, but it calls this function internally because the user context is actually
1156:    associated with the `DM`.  This makes the interface consistent regardless of whether the user interacts with a `DM` or
1157:    not.

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

1162: .seealso: [](chapter_ts), `DMTSSetContext()`, `TSSetFunction()`, `DMTSGetJacobian()`, `TSSetRHSJacobian()`
1163: @*/
1164: PetscErrorCode DMTSSetRHSJacobian(DM dm, TSRHSJacobian func, void *ctx)
1165: {
1166:   DMTS tsdm;

1169:   DMGetDMTSWrite(dm, &tsdm);
1170:   if (func) tsdm->ops->rhsjacobian = func;
1171:   if (ctx) {
1172:     PetscContainer ctxcontainer;
1173:     PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer);
1174:     PetscContainerSetPointer(ctxcontainer, ctx);
1175:     PetscObjectCompose((PetscObject)tsdm, "rhs jacobian ctx", (PetscObject)ctxcontainer);
1176:     tsdm->rhsjacobianctxcontainer = ctxcontainer;
1177:     PetscContainerDestroy(&ctxcontainer);
1178:   }
1179:   return 0;
1180: }

1182: /*@C
1183:    DMTSSetRHSJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function

1185:    Not Collective

1187:    Input Parameters:
1188: +  dm - `DM` to be used with `TS`
1189: -  f - Jacobian evaluation context destroy function

1191:    Level: advanced

1193:    Note:
1194:    The user usually calls `TSSetRHSJacobianContextDestroy()` which calls this routine

1196: .seealso: [](chapter_ts), `TS`, `TSSetRHSJacobianContextDestroy()`, `DMTSSetRHSJacobian()`, `TSSetRHSJacobian()`
1197: @*/
1198: PetscErrorCode DMTSSetRHSJacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
1199: {
1200:   DMTS tsdm;

1203:   DMGetDMTSWrite(dm, &tsdm);
1204:   if (tsdm->rhsjacobianctxcontainer) PetscContainerSetUserDestroy(tsdm->rhsjacobianctxcontainer, f);
1205:   return 0;
1206: }

1208: PetscErrorCode DMTSUnsetRHSJacobianContext_Internal(DM dm)
1209: {
1210:   DMTS tsdm;

1213:   DMGetDMTSWrite(dm, &tsdm);
1214:   DMTSUnsetRHSJacobianContext_DMTS(tsdm);
1215:   return 0;
1216: }

1218: /*@C
1219:    DMTSGetRHSJacobian - get `TS` Jacobian evaluation function

1221:    Not Collective

1223:    Input Parameter:
1224: .  dm - `DM` to be used with `TS`

1226:    Output Parameters:
1227: +  func - Jacobian evaluation function, see `TSSetRHSJacobian()` for calling sequence
1228: -  ctx - context for residual evaluation

1230:    Level: advanced

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

1237: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetRHSFunction()`, `DMTSSetRHSJacobian()`, `TSSetRHSJacobian()`
1238: @*/
1239: PetscErrorCode DMTSGetRHSJacobian(DM dm, TSRHSJacobian *func, void **ctx)
1240: {
1241:   DMTS tsdm;

1244:   DMGetDMTS(dm, &tsdm);
1245:   if (func) *func = tsdm->ops->rhsjacobian;
1246:   if (ctx) {
1247:     if (tsdm->rhsjacobianctxcontainer) PetscContainerGetPointer(tsdm->rhsjacobianctxcontainer, ctx);
1248:     else *ctx = NULL;
1249:   }
1250:   return 0;
1251: }

1253: /*@C
1254:    DMTSSetIFunctionSerialize - sets functions used to view and load a IFunction context

1256:    Not Collective

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

1263:    Level: advanced

1265: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`
1266: @*/
1267: PetscErrorCode DMTSSetIFunctionSerialize(DM dm, PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*load)(void **, PetscViewer))
1268: {
1269:   DMTS tsdm;

1272:   DMGetDMTSWrite(dm, &tsdm);
1273:   tsdm->ops->ifunctionview = view;
1274:   tsdm->ops->ifunctionload = load;
1275:   return 0;
1276: }

1278: /*@C
1279:    DMTSSetIJacobianSerialize - sets functions used to view and load a IJacobian context

1281:    Not Collective

1283:    Input Parameters:
1284: +  dm - `DM` to be used with `TS`
1285: .  view - viewer function
1286: -  load - loading function

1288:    Level: advanced

1290: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`
1291: @*/
1292: PetscErrorCode DMTSSetIJacobianSerialize(DM dm, PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*load)(void **, PetscViewer))
1293: {
1294:   DMTS tsdm;

1297:   DMGetDMTSWrite(dm, &tsdm);
1298:   tsdm->ops->ijacobianview = view;
1299:   tsdm->ops->ijacobianload = load;
1300:   return 0;
1301: }