Actual source code: dmts.c

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

204:    Not Collective

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

210:    Level: developer

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

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

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

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

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

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

259:    Not Collective

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

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

267:    Level: developer

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

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

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

293:    Not Collective

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

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

301:    Level: developer

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

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

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

329:    Logically Collective

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

335:    Level: developer

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

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

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

358:    Not Collective

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

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

368: +  t   - time at step/stage being solved
369: .  u   - state vector
370: .  u_t - time derivative of state vector
371: .  F   - function vector
372: -  ctx - [optional] user-defined context for matrix evaluation routine

374:    Level: advanced

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

381: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `TSSetIFunction()`, `DMTSSetJacobian()`
382: @*/
383: PetscErrorCode DMTSSetIFunction(DM dm, TSIFunction func, void *ctx)
384: {
385:   DMTS tsdm;

387:   PetscFunctionBegin;
389:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
390:   if (func) tsdm->ops->ifunction = func;
391:   if (ctx) {
392:     PetscContainer ctxcontainer;
393:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
394:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
395:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "ifunction ctx", (PetscObject)ctxcontainer));
396:     tsdm->ifunctionctxcontainer = ctxcontainer;
397:     PetscCall(PetscContainerDestroy(&ctxcontainer));
398:   }
399:   PetscFunctionReturn(PETSC_SUCCESS);
400: }

402: /*@C
403:    DMTSSetIFunctionContextDestroy - set `TS` implicit evaluation context destroy function

405:    Not Collective

407:    Input Parameters:
408: +  dm - `DM` to be used with `TS`
409: -  f - implicit evaluation context destroy function

411:    Level: advanced

413: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetIFunction()`, `TSSetIFunction()`
414: @*/
415: PetscErrorCode DMTSSetIFunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *))
416: {
417:   DMTS tsdm;

419:   PetscFunctionBegin;
421:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
422:   if (tsdm->ifunctionctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->ifunctionctxcontainer, f));
423:   PetscFunctionReturn(PETSC_SUCCESS);
424: }

426: PetscErrorCode DMTSUnsetIFunctionContext_Internal(DM dm)
427: {
428:   DMTS tsdm;

430:   PetscFunctionBegin;
432:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
433:   PetscCall(DMTSUnsetIFunctionContext_DMTS(tsdm));
434:   PetscFunctionReturn(PETSC_SUCCESS);
435: }

437: /*@C
438:    DMTSGetIFunction - get `TS` implicit residual evaluation function

440:    Not Collective

442:    Input Parameter:
443: .  dm - `DM` to be used with `TS`

445:    Output Parameters:
446: +  func - function evaluation function, see `TSSetIFunction()` for calling sequence
447: -  ctx - context for residual evaluation

449:    Level: advanced

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

455: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `DMTSSetFunction()`, `TSSetFunction()`
456: @*/
457: PetscErrorCode DMTSGetIFunction(DM dm, TSIFunction *func, void **ctx)
458: {
459:   DMTS tsdm;

461:   PetscFunctionBegin;
463:   PetscCall(DMGetDMTS(dm, &tsdm));
464:   if (func) *func = tsdm->ops->ifunction;
465:   if (ctx) {
466:     if (tsdm->ifunctionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->ifunctionctxcontainer, ctx));
467:     else *ctx = NULL;
468:   }
469:   PetscFunctionReturn(PETSC_SUCCESS);
470: }

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

475:    Not Collective

477:    Input Parameters:
478: +  dm - `DM` to be used with `TS`
479: .  fun - function evaluation routine
480: -  ctx - context for residual evaluation

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

485: +  t    - time at step/stage being solved
486: .  U    - state vector
487: .  U_t  - time derivative of state vector
488: .  U_tt - second time derivative of state vector
489: .  F    - function vector
490: -  ctx  - [optional] user-defined context for matrix evaluation routine (may be NULL)

492:    Level: advanced

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

498: .seealso: [](chapter_ts), `DM`, `TS`, `TSSetI2Function()`
499: @*/
500: PetscErrorCode DMTSSetI2Function(DM dm, TSI2Function fun, void *ctx)
501: {
502:   DMTS tsdm;

504:   PetscFunctionBegin;
506:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
507:   if (fun) tsdm->ops->i2function = fun;
508:   if (ctx) {
509:     PetscContainer ctxcontainer;
510:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
511:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
512:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "i2function ctx", (PetscObject)ctxcontainer));
513:     tsdm->i2functionctxcontainer = ctxcontainer;
514:     PetscCall(PetscContainerDestroy(&ctxcontainer));
515:   }
516:   PetscFunctionReturn(PETSC_SUCCESS);
517: }

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

522:    Not Collective

524:    Input Parameters:
525: +  dm - `DM` to be used with `TS`
526: -  f - implicit evaluation context destroy function

528:    Level: advanced

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

534: .seealso: [](chapter_ts), `TSSetI2FunctionContextDestroy()`, `DMTSSetI2Function()`, `TSSetI2Function()`
535: @*/
536: PetscErrorCode DMTSSetI2FunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *))
537: {
538:   DMTS tsdm;

540:   PetscFunctionBegin;
542:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
543:   if (tsdm->i2functionctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->i2functionctxcontainer, f));
544:   PetscFunctionReturn(PETSC_SUCCESS);
545: }

547: PetscErrorCode DMTSUnsetI2FunctionContext_Internal(DM dm)
548: {
549:   DMTS tsdm;

551:   PetscFunctionBegin;
553:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
554:   PetscCall(DMTSUnsetI2FunctionContext_DMTS(tsdm));
555:   PetscFunctionReturn(PETSC_SUCCESS);
556: }

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

561:    Not Collective

563:    Input Parameter:
564: .  dm - `DM` to be used with `TS`

566:    Output Parameters:
567: +  fun - function evaluation function, see `TSSetI2Function()` for calling sequence
568: -  ctx - context for residual evaluation

570:    Level: advanced

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

576: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetI2Function()`, `TSGetI2Function()`
577: @*/
578: PetscErrorCode DMTSGetI2Function(DM dm, TSI2Function *fun, void **ctx)
579: {
580:   DMTS tsdm;

582:   PetscFunctionBegin;
584:   PetscCall(DMGetDMTS(dm, &tsdm));
585:   if (fun) *fun = tsdm->ops->i2function;
586:   if (ctx) {
587:     if (tsdm->i2functionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->i2functionctxcontainer, ctx));
588:     else *ctx = NULL;
589:   }
590:   PetscFunctionReturn(PETSC_SUCCESS);
591: }

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

596:    Not Collective

598:    Input Parameters:
599: +  dm - `DM` to be used with `TS`
600: .  fun - Jacobian evaluation routine
601: -  ctx - context for Jacobian evaluation

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

606: +  t    - time at step/stage being solved
607: .  U    - state vector
608: .  U_t  - time derivative of state vector
609: .  U_tt - second time derivative of state vector
610: .  v    - shift for U_t
611: .  a    - shift for U_tt
612: .  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
613: .  P    - preconditioning matrix for J, may be same as J
614: -  ctx  - [optional] user-defined context for matrix evaluation routine

616:    Level: advanced

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

622: .seealso: [](chapter_ts), `DM`, `TS`, `TSSetI2Jacobian()`
623: @*/
624: PetscErrorCode DMTSSetI2Jacobian(DM dm, TSI2Jacobian jac, void *ctx)
625: {
626:   DMTS tsdm;

628:   PetscFunctionBegin;
630:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
631:   if (jac) tsdm->ops->i2jacobian = jac;
632:   if (ctx) {
633:     PetscContainer ctxcontainer;
634:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
635:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
636:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "i2jacobian ctx", (PetscObject)ctxcontainer));
637:     tsdm->i2jacobianctxcontainer = ctxcontainer;
638:     PetscCall(PetscContainerDestroy(&ctxcontainer));
639:   }
640:   PetscFunctionReturn(PETSC_SUCCESS);
641: }

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

646:    Not Collective

648:    Input Parameters:
649: +  dm - `DM` to be used with `TS`
650: -  f - implicit Jacobian evaluation context destroy function

652:    Level: advanced

654: .seealso: [](chapter_ts), `DM`, `TS`, `TSSetI2JacobianContextDestroy()`, `DMTSSetI2Jacobian()`, `TSSetI2Jacobian()`
655: @*/
656: PetscErrorCode DMTSSetI2JacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
657: {
658:   DMTS tsdm;

660:   PetscFunctionBegin;
662:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
663:   if (tsdm->i2jacobianctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->i2jacobianctxcontainer, f));
664:   PetscFunctionReturn(PETSC_SUCCESS);
665: }

667: PetscErrorCode DMTSUnsetI2JacobianContext_Internal(DM dm)
668: {
669:   DMTS tsdm;

671:   PetscFunctionBegin;
673:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
674:   PetscCall(DMTSUnsetI2JacobianContext_DMTS(tsdm));
675:   PetscFunctionReturn(PETSC_SUCCESS);
676: }

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

681:    Not Collective

683:    Input Parameter:
684: .  dm - `DM` to be used with `TS`

686:    Output Parameters:
687: +  jac - Jacobian evaluation function, see `TSSetI2Jacobian()` for calling sequence
688: -  ctx - context for Jacobian evaluation

690:    Level: advanced

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

696: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetI2Jacobian()`, `TSGetI2Jacobian()`
697: @*/
698: PetscErrorCode DMTSGetI2Jacobian(DM dm, TSI2Jacobian *jac, void **ctx)
699: {
700:   DMTS tsdm;

702:   PetscFunctionBegin;
704:   PetscCall(DMGetDMTS(dm, &tsdm));
705:   if (jac) *jac = tsdm->ops->i2jacobian;
706:   if (ctx) {
707:     if (tsdm->i2jacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->i2jacobianctxcontainer, ctx));
708:     else *ctx = NULL;
709:   }
710:   PetscFunctionReturn(PETSC_SUCCESS);
711: }

713: /*@C
714:    DMTSSetRHSFunction - set `TS` explicit residual evaluation function

716:    Not Collective

718:    Input Parameters:
719: +  dm - `DM` to be used with `TS`
720: .  func - RHS function evaluation routine
721: -  ctx - context for residual evaluation

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

726: +   ts - timestep context
727: .   t - current timestep
728: .   u - input vector
729: .   F - function vector
730: -   ctx - [optional] user-defined function context

732:    Level: advanced

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

739: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetRHSFunction()`, `DMTSSetJacobian()`
740: @*/
741: PetscErrorCode DMTSSetRHSFunction(DM dm, TSRHSFunction func, void *ctx)
742: {
743:   DMTS tsdm;

745:   PetscFunctionBegin;
747:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
748:   if (func) tsdm->ops->rhsfunction = func;
749:   if (ctx) {
750:     PetscContainer ctxcontainer;
751:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
752:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
753:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "rhs function ctx", (PetscObject)ctxcontainer));
754:     tsdm->rhsfunctionctxcontainer = ctxcontainer;
755:     PetscCall(PetscContainerDestroy(&ctxcontainer));
756:   }
757:   PetscFunctionReturn(PETSC_SUCCESS);
758: }

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

763:    Not Collective

765:    Input Parameters:
766: +  dm - `DM` to be used with `TS`
767: -  f - explicit evaluation context destroy function

769:    Level: advanced

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

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

779: .seealso: [](chapter_ts), `TSSetRHSFunctionContextDestroy()`, `DMTSSetRHSFunction()`, `TSSetRHSFunction()`
780: @*/
781: PetscErrorCode DMTSSetRHSFunctionContextDestroy(DM dm, PetscErrorCode (*f)(void *))
782: {
783:   DMTS tsdm;

785:   PetscFunctionBegin;
787:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
788:   if (tsdm->rhsfunctionctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->rhsfunctionctxcontainer, f));
789:   PetscFunctionReturn(PETSC_SUCCESS);
790: }

792: PetscErrorCode DMTSUnsetRHSFunctionContext_Internal(DM dm)
793: {
794:   DMTS tsdm;

796:   PetscFunctionBegin;
798:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
799:   PetscCall(DMTSUnsetRHSFunctionContext_DMTS(tsdm));
800:   tsdm->rhsfunctionctxcontainer = NULL;
801:   PetscFunctionReturn(PETSC_SUCCESS);
802: }

804: /*@C
805:    DMTSSetTransientVariable - sets function to transform from state to transient variables

807:    Logically Collective

809:    Input Parameters:
810: +  dm - `DM` to be used with `TS`
811: .  tvar - a function that transforms to transient variables
812: -  ctx - a context for tvar

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

817: +   ts - timestep context
818: .   p - input vector (primitive form)
819: .   c - output vector, transient variables (conservative form)
820: -   ctx - [optional] user-defined function context

822:    Level: advanced

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

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

833: .seealso: [](chapter_ts), `TS`, `TSBDF`, `TSSetTransientVariable()`, `DMTSGetTransientVariable()`, `DMTSSetIFunction()`, `DMTSSetIJacobian()`
834: @*/
835: PetscErrorCode DMTSSetTransientVariable(DM dm, TSTransientVariable tvar, void *ctx)
836: {
837:   DMTS dmts;

839:   PetscFunctionBegin;
841:   PetscCall(DMGetDMTSWrite(dm, &dmts));
842:   dmts->ops->transientvar = tvar;
843:   dmts->transientvarctx   = ctx;
844:   PetscFunctionReturn(PETSC_SUCCESS);
845: }

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

850:    Logically Collective

852:    Input Parameter:
853: .  dm - `DM` to be used with `TS`

855:    Output Parameters:
856: +  tvar - a function that transforms to transient variables
857: -  ctx - a context for tvar

859:    Level: advanced

861: .seealso: [](chapter_ts), `DM`, `DMTSSetTransientVariable()`, `DMTSGetIFunction()`, `DMTSGetIJacobian()`
862: @*/
863: PetscErrorCode DMTSGetTransientVariable(DM dm, TSTransientVariable *tvar, void *ctx)
864: {
865:   DMTS dmts;

867:   PetscFunctionBegin;
869:   PetscCall(DMGetDMTS(dm, &dmts));
870:   if (tvar) *tvar = dmts->ops->transientvar;
871:   if (ctx) *(void **)ctx = dmts->transientvarctx;
872:   PetscFunctionReturn(PETSC_SUCCESS);
873: }

875: /*@C
876:    DMTSGetSolutionFunction - gets the `TS` solution evaluation function

878:    Not Collective

880:    Input Parameter:
881: .  dm - `DM` to be used with `TS`

883:    Output Parameters:
884: +  func - solution function evaluation function, see `TSSetSolution()` for calling sequence
885: -  ctx - context for solution evaluation

887:    Level: advanced

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

895:   PetscFunctionBegin;
897:   PetscCall(DMGetDMTS(dm, &tsdm));
898:   if (func) *func = tsdm->ops->solution;
899:   if (ctx) *ctx = tsdm->solutionctx;
900:   PetscFunctionReturn(PETSC_SUCCESS);
901: }

903: /*@C
904:    DMTSSetSolutionFunction - set `TS` solution evaluation function

906:    Not Collective

908:    Input Parameters:
909: +  dm - `DM` to be used with `TS`
910: .  func - solution function evaluation routine
911: -  ctx - context for solution evaluation

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

916: +   ts - timestep context
917: .   t - current timestep
918: .   u - output vector
919: -   ctx - [optional] user-defined function context

921:    Level: advanced

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

928: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`, `DMTSGetSolutionFunction()`
929: @*/
930: PetscErrorCode DMTSSetSolutionFunction(DM dm, TSSolutionFunction func, void *ctx)
931: {
932:   DMTS tsdm;

934:   PetscFunctionBegin;
936:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
937:   if (func) tsdm->ops->solution = func;
938:   if (ctx) tsdm->solutionctx = ctx;
939:   PetscFunctionReturn(PETSC_SUCCESS);
940: }

942: /*@C
943:    DMTSSetForcingFunction - set `TS` forcing function evaluation function

945:    Not Collective

947:    Input Parameters:
948: +  dm - `DM` to be used with `TS`
949: .  f - forcing function evaluation routine
950: -  ctx - context for solution evaluation

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

955: +   ts - timestep context
956: .   t - current timestep
957: .   f - output vector
958: -   ctx - [optional] user-defined function context

960:    Level: advanced

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

967: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`, `TSSetForcingFunction()`, `DMTSGetForcingFunction()`
968: @*/
969: PetscErrorCode DMTSSetForcingFunction(DM dm, TSForcingFunction f, void *ctx)
970: {
971:   DMTS tsdm;

973:   PetscFunctionBegin;
975:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
976:   if (f) tsdm->ops->forcing = f;
977:   if (ctx) tsdm->forcingctx = ctx;
978:   PetscFunctionReturn(PETSC_SUCCESS);
979: }

981: /*@C
982:    DMTSGetForcingFunction - get `TS` forcing function evaluation function

984:    Not Collective

986:    Input Parameter:
987: .   dm - `DM` to be used with `TS`

989:    Output Parameters:
990: +  f - forcing function evaluation function; see `TSForcingFunction` for details
991: -  ctx - context for solution evaluation

993:    Level: advanced

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

1000: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`, `TSSetForcingFunction()`, `DMTSGetForcingFunction()`
1001: @*/
1002: PetscErrorCode DMTSGetForcingFunction(DM dm, TSForcingFunction *f, void **ctx)
1003: {
1004:   DMTS tsdm;

1006:   PetscFunctionBegin;
1008:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1009:   if (f) *f = tsdm->ops->forcing;
1010:   if (ctx) *ctx = tsdm->forcingctx;
1011:   PetscFunctionReturn(PETSC_SUCCESS);
1012: }

1014: /*@C
1015:    DMTSGetRHSFunction - get `TS` explicit residual evaluation function

1017:    Not Collective

1019:    Input Parameter:
1020: .  dm - `DM` to be used with `TS`

1022:    Output Parameters:
1023: +  func - residual evaluation function, see `TSSetRHSFunction()` for calling sequence
1024: -  ctx - context for residual evaluation

1026:    Level: advanced

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

1032: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `DMTSSetRHSFunction()`, `TSSetRHSFunction()`
1033: @*/
1034: PetscErrorCode DMTSGetRHSFunction(DM dm, TSRHSFunction *func, void **ctx)
1035: {
1036:   DMTS tsdm;

1038:   PetscFunctionBegin;
1040:   PetscCall(DMGetDMTS(dm, &tsdm));
1041:   if (func) *func = tsdm->ops->rhsfunction;
1042:   if (ctx) {
1043:     if (tsdm->rhsfunctionctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->rhsfunctionctxcontainer, ctx));
1044:     else *ctx = NULL;
1045:   }
1046:   PetscFunctionReturn(PETSC_SUCCESS);
1047: }

1049: /*@C
1050:    DMTSSetIJacobian - set `TS` Jacobian evaluation function

1052:    Not Collective

1054:    Input Parameters:
1055: +  dm - `DM` to be used with `TS`
1056: .  func - Jacobian evaluation routine
1057: -  ctx - context for residual evaluation

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

1062: +  t    - time at step/stage being solved
1063: .  U    - state vector
1064: .  U_t  - time derivative of state vector
1065: .  a    - shift
1066: .  Amat - (approximate) Jacobian of F(t,U,W+a*U), equivalent to dF/dU + a*dF/dU_t
1067: .  Pmat - matrix used for constructing preconditioner, usually the same as Amat
1068: -  ctx  - [optional] user-defined context for matrix evaluation routine

1070:    Level: advanced

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

1077: .seealso: [](chapter_ts), `TS`, `DM`, `DMTSSetContext()`, `TSSetRHSFunction()`, `DMTSGetJacobian()`, `TSSetIJacobian()`, `TSSetIFunction()`
1078: @*/
1079: PetscErrorCode DMTSSetIJacobian(DM dm, TSIJacobian func, void *ctx)
1080: {
1081:   DMTS tsdm;

1083:   PetscFunctionBegin;
1085:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1086:   if (func) tsdm->ops->ijacobian = func;
1087:   if (ctx) {
1088:     PetscContainer ctxcontainer;
1089:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
1090:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1091:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "ijacobian ctx", (PetscObject)ctxcontainer));
1092:     tsdm->ijacobianctxcontainer = ctxcontainer;
1093:     PetscCall(PetscContainerDestroy(&ctxcontainer));
1094:   }
1095:   PetscFunctionReturn(PETSC_SUCCESS);
1096: }

1098: /*@C
1099:    DMTSSetIJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function

1101:    Not Collective

1103:    Input Parameters:
1104: +  dm - `DM` to be used with `TS`
1105: -  f - Jacobian evaluation context destroy function

1107:    Level: advanced

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

1114:    Developer Note:
1115:    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), `TSSetIJacobianContextDestroy()`, `TSSetI2JacobianContextDestroy()`, `DMTSSetIJacobian()`, `TSSetIJacobian()`
1118: @*/
1119: PetscErrorCode DMTSSetIJacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
1120: {
1121:   DMTS tsdm;

1123:   PetscFunctionBegin;
1125:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1126:   if (tsdm->ijacobianctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->ijacobianctxcontainer, f));
1127:   PetscFunctionReturn(PETSC_SUCCESS);
1128: }

1130: PetscErrorCode DMTSUnsetIJacobianContext_Internal(DM dm)
1131: {
1132:   DMTS tsdm;

1134:   PetscFunctionBegin;
1136:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1137:   PetscCall(DMTSUnsetIJacobianContext_DMTS(tsdm));
1138:   PetscFunctionReturn(PETSC_SUCCESS);
1139: }

1141: /*@C
1142:    DMTSGetIJacobian - get `TS` Jacobian evaluation function

1144:    Not Collective

1146:    Input Parameter:
1147: .  dm - `DM` to be used with `TS`

1149:    Output Parameters:
1150: +  func - Jacobian evaluation function, see `TSSetIJacobian()` for calling sequence
1151: -  ctx - context for residual evaluation

1153:    Level: advanced

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

1160: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`
1161: @*/
1162: PetscErrorCode DMTSGetIJacobian(DM dm, TSIJacobian *func, void **ctx)
1163: {
1164:   DMTS tsdm;

1166:   PetscFunctionBegin;
1168:   PetscCall(DMGetDMTS(dm, &tsdm));
1169:   if (func) *func = tsdm->ops->ijacobian;
1170:   if (ctx) {
1171:     if (tsdm->ijacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->ijacobianctxcontainer, ctx));
1172:     else *ctx = NULL;
1173:   }
1174:   PetscFunctionReturn(PETSC_SUCCESS);
1175: }

1177: /*@C
1178:    DMTSSetRHSJacobian - set `TS` Jacobian evaluation function

1180:    Not Collective

1182:    Input Parameters:
1183: +  dm - `DM` to be used with `TS`
1184: .  func - Jacobian evaluation routine
1185: -  ctx - context for residual evaluation

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

1190: +  t - current timestep
1191: .  u - input vector
1192: .  Amat - (approximate) Jacobian matrix
1193: .  Pmat - matrix from which preconditioner is to be constructed (usually the same as Amat)
1194: -  ctx - [optional] user-defined context for matrix evaluation routine

1196:    Level: advanced

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

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

1206: .seealso: [](chapter_ts), `DMTSSetContext()`, `TSSetFunction()`, `DMTSGetJacobian()`, `TSSetRHSJacobian()`
1207: @*/
1208: PetscErrorCode DMTSSetRHSJacobian(DM dm, TSRHSJacobian func, void *ctx)
1209: {
1210:   DMTS tsdm;

1212:   PetscFunctionBegin;
1214:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1215:   if (func) tsdm->ops->rhsjacobian = func;
1216:   if (ctx) {
1217:     PetscContainer ctxcontainer;
1218:     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)tsdm), &ctxcontainer));
1219:     PetscCall(PetscContainerSetPointer(ctxcontainer, ctx));
1220:     PetscCall(PetscObjectCompose((PetscObject)tsdm, "rhs jacobian ctx", (PetscObject)ctxcontainer));
1221:     tsdm->rhsjacobianctxcontainer = ctxcontainer;
1222:     PetscCall(PetscContainerDestroy(&ctxcontainer));
1223:   }
1224:   PetscFunctionReturn(PETSC_SUCCESS);
1225: }

1227: /*@C
1228:    DMTSSetRHSJacobianContextDestroy - set `TS` Jacobian evaluation context destroy function

1230:    Not Collective

1232:    Input Parameters:
1233: +  dm - `DM` to be used with `TS`
1234: -  f - Jacobian evaluation context destroy function

1236:    Level: advanced

1238:    Note:
1239:    The user usually calls `TSSetRHSJacobianContextDestroy()` which calls this routine

1241: .seealso: [](chapter_ts), `TS`, `TSSetRHSJacobianContextDestroy()`, `DMTSSetRHSJacobian()`, `TSSetRHSJacobian()`
1242: @*/
1243: PetscErrorCode DMTSSetRHSJacobianContextDestroy(DM dm, PetscErrorCode (*f)(void *))
1244: {
1245:   DMTS tsdm;

1247:   PetscFunctionBegin;
1249:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1250:   if (tsdm->rhsjacobianctxcontainer) PetscCall(PetscContainerSetUserDestroy(tsdm->rhsjacobianctxcontainer, f));
1251:   PetscFunctionReturn(PETSC_SUCCESS);
1252: }

1254: PetscErrorCode DMTSUnsetRHSJacobianContext_Internal(DM dm)
1255: {
1256:   DMTS tsdm;

1258:   PetscFunctionBegin;
1260:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1261:   PetscCall(DMTSUnsetRHSJacobianContext_DMTS(tsdm));
1262:   PetscFunctionReturn(PETSC_SUCCESS);
1263: }

1265: /*@C
1266:    DMTSGetRHSJacobian - get `TS` Jacobian evaluation function

1268:    Not Collective

1270:    Input Parameter:
1271: .  dm - `DM` to be used with `TS`

1273:    Output Parameters:
1274: +  func - Jacobian evaluation function, see `TSSetRHSJacobian()` for calling sequence
1275: -  ctx - context for residual evaluation

1277:    Level: advanced

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

1284: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetRHSFunction()`, `DMTSSetRHSJacobian()`, `TSSetRHSJacobian()`
1285: @*/
1286: PetscErrorCode DMTSGetRHSJacobian(DM dm, TSRHSJacobian *func, void **ctx)
1287: {
1288:   DMTS tsdm;

1290:   PetscFunctionBegin;
1292:   PetscCall(DMGetDMTS(dm, &tsdm));
1293:   if (func) *func = tsdm->ops->rhsjacobian;
1294:   if (ctx) {
1295:     if (tsdm->rhsjacobianctxcontainer) PetscCall(PetscContainerGetPointer(tsdm->rhsjacobianctxcontainer, ctx));
1296:     else *ctx = NULL;
1297:   }
1298:   PetscFunctionReturn(PETSC_SUCCESS);
1299: }

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

1304:    Not Collective

1306:    Input Parameters:
1307: +  dm - `DM` to be used with `TS`
1308: .  view - viewer function
1309: -  load - loading function

1311:    Level: advanced

1313: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`
1314: @*/
1315: PetscErrorCode DMTSSetIFunctionSerialize(DM dm, PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*load)(void **, PetscViewer))
1316: {
1317:   DMTS tsdm;

1319:   PetscFunctionBegin;
1321:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1322:   tsdm->ops->ifunctionview = view;
1323:   tsdm->ops->ifunctionload = load;
1324:   PetscFunctionReturn(PETSC_SUCCESS);
1325: }

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

1330:    Not Collective

1332:    Input Parameters:
1333: +  dm - `DM` to be used with `TS`
1334: .  view - viewer function
1335: -  load - loading function

1337:    Level: advanced

1339: .seealso: [](chapter_ts), `DM`, `TS`, `DMTSSetContext()`, `TSSetFunction()`, `DMTSSetJacobian()`
1340: @*/
1341: PetscErrorCode DMTSSetIJacobianSerialize(DM dm, PetscErrorCode (*view)(void *, PetscViewer), PetscErrorCode (*load)(void **, PetscViewer))
1342: {
1343:   DMTS tsdm;

1345:   PetscFunctionBegin;
1347:   PetscCall(DMGetDMTSWrite(dm, &tsdm));
1348:   tsdm->ops->ijacobianview = view;
1349:   tsdm->ops->ijacobianload = load;
1350:   PetscFunctionReturn(PETSC_SUCCESS);
1351: }