Actual source code: dmlocalts.c

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

  4: typedef struct {
  5:   PetscErrorCode (*boundarylocal)(DM, PetscReal, Vec, Vec, void *);
  6:   PetscErrorCode (*ifunctionlocal)(DM, PetscReal, Vec, Vec, Vec, void *);
  7:   PetscErrorCode (*ijacobianlocal)(DM, PetscReal, Vec, Vec, PetscReal, Mat, Mat, void *);
  8:   PetscErrorCode (*rhsfunctionlocal)(DM, PetscReal, Vec, Vec, void *);
  9:   void *boundarylocalctx;
 10:   void *ifunctionlocalctx;
 11:   void *ijacobianlocalctx;
 12:   void *rhsfunctionlocalctx;
 13:   Vec   lumpedmassinv;
 14:   Mat   mass;
 15:   KSP   kspmass;
 16: } DMTS_Local;

 18: static PetscErrorCode DMTSDestroy_DMLocal(DMTS tdm)
 19: {
 20:   PetscFunctionBegin;
 21:   PetscCall(PetscFree(tdm->data));
 22:   PetscFunctionReturn(PETSC_SUCCESS);
 23: }

 25: static PetscErrorCode DMTSDuplicate_DMLocal(DMTS oldtdm, DMTS tdm)
 26: {
 27:   PetscFunctionBegin;
 28:   PetscCall(PetscNew((DMTS_Local **)&tdm->data));
 29:   if (oldtdm->data) PetscCall(PetscMemcpy(tdm->data, oldtdm->data, sizeof(DMTS_Local)));
 30:   PetscFunctionReturn(PETSC_SUCCESS);
 31: }

 33: static PetscErrorCode DMLocalTSGetContext(DM dm, DMTS tdm, DMTS_Local **dmlocalts)
 34: {
 35:   PetscFunctionBegin;
 36:   *dmlocalts = NULL;
 37:   if (!tdm->data) {
 38:     PetscCall(PetscNew((DMTS_Local **)&tdm->data));

 40:     tdm->ops->destroy   = DMTSDestroy_DMLocal;
 41:     tdm->ops->duplicate = DMTSDuplicate_DMLocal;
 42:   }
 43:   *dmlocalts = (DMTS_Local *)tdm->data;
 44:   PetscFunctionReturn(PETSC_SUCCESS);
 45: }

 47: static PetscErrorCode TSComputeIFunction_DMLocal(TS ts, PetscReal time, Vec X, Vec X_t, Vec F, void *ctx)
 48: {
 49:   DM          dm;
 50:   Vec         locX, locX_t, locF;
 51:   DMTS_Local *dmlocalts = (DMTS_Local *)ctx;

 53:   PetscFunctionBegin;
 58:   PetscCall(TSGetDM(ts, &dm));
 59:   PetscCall(DMGetLocalVector(dm, &locX));
 60:   PetscCall(DMGetLocalVector(dm, &locX_t));
 61:   PetscCall(DMGetLocalVector(dm, &locF));
 62:   PetscCall(VecZeroEntries(locX));
 63:   PetscCall(VecZeroEntries(locX_t));
 64:   if (dmlocalts->boundarylocal) PetscCall((*dmlocalts->boundarylocal)(dm, time, locX, locX_t, dmlocalts->boundarylocalctx));
 65:   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
 66:   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
 67:   PetscCall(DMGlobalToLocalBegin(dm, X_t, INSERT_VALUES, locX_t));
 68:   PetscCall(DMGlobalToLocalEnd(dm, X_t, INSERT_VALUES, locX_t));
 69:   PetscCall(VecZeroEntries(locF));
 70:   CHKMEMQ;
 71:   PetscCall((*dmlocalts->ifunctionlocal)(dm, time, locX, locX_t, locF, dmlocalts->ifunctionlocalctx));
 72:   CHKMEMQ;
 73:   PetscCall(VecZeroEntries(F));
 74:   PetscCall(DMLocalToGlobalBegin(dm, locF, ADD_VALUES, F));
 75:   PetscCall(DMLocalToGlobalEnd(dm, locF, ADD_VALUES, F));
 76:   PetscCall(DMRestoreLocalVector(dm, &locX));
 77:   PetscCall(DMRestoreLocalVector(dm, &locX_t));
 78:   PetscCall(DMRestoreLocalVector(dm, &locF));

 80:   /* remove nullspace from residual */
 81:   {
 82:     MatNullSpace nullsp;
 83:     PetscCall(PetscObjectQuery((PetscObject)dm, "__dmtsnullspace", (PetscObject *)&nullsp));
 84:     if (nullsp) PetscCall(MatNullSpaceRemove(nullsp, F));
 85:   }
 86:   PetscFunctionReturn(PETSC_SUCCESS);
 87: }

 89: static PetscErrorCode TSComputeRHSFunction_DMLocal(TS ts, PetscReal time, Vec X, Vec F, void *ctx)
 90: {
 91:   DM          dm;
 92:   Vec         locX, locF;
 93:   DMTS_Local *dmlocalts = (DMTS_Local *)ctx;

 95:   PetscFunctionBegin;
 99:   PetscCall(TSGetDM(ts, &dm));
100:   PetscCall(DMGetLocalVector(dm, &locX));
101:   PetscCall(DMGetLocalVector(dm, &locF));
102:   PetscCall(VecZeroEntries(locX));
103:   if (dmlocalts->boundarylocal) PetscCall((*dmlocalts->boundarylocal)(dm, time, locX, NULL, dmlocalts->boundarylocalctx));
104:   PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
105:   PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
106:   PetscCall(VecZeroEntries(locF));
107:   CHKMEMQ;
108:   PetscCall((*dmlocalts->rhsfunctionlocal)(dm, time, locX, locF, dmlocalts->rhsfunctionlocalctx));
109:   CHKMEMQ;
110:   PetscCall(VecZeroEntries(F));
111:   PetscCall(DMLocalToGlobalBegin(dm, locF, ADD_VALUES, F));
112:   PetscCall(DMLocalToGlobalEnd(dm, locF, ADD_VALUES, F));
113:   if (dmlocalts->lumpedmassinv) {
114:     PetscCall(VecPointwiseMult(F, dmlocalts->lumpedmassinv, F));
115:   } else if (dmlocalts->kspmass) {
116:     Vec tmp;

118:     PetscCall(DMGetGlobalVector(dm, &tmp));
119:     PetscCall(KSPSolve(dmlocalts->kspmass, F, tmp));
120:     PetscCall(VecCopy(tmp, F));
121:     PetscCall(DMRestoreGlobalVector(dm, &tmp));
122:   }
123:   PetscCall(DMRestoreLocalVector(dm, &locX));
124:   PetscCall(DMRestoreLocalVector(dm, &locF));
125:   PetscFunctionReturn(PETSC_SUCCESS);
126: }

128: static PetscErrorCode TSComputeIJacobian_DMLocal(TS ts, PetscReal time, Vec X, Vec X_t, PetscReal a, Mat A, Mat B, void *ctx)
129: {
130:   DM          dm;
131:   Vec         locX, locX_t;
132:   DMTS_Local *dmlocalts = (DMTS_Local *)ctx;

134:   PetscFunctionBegin;
135:   PetscCall(TSGetDM(ts, &dm));
136:   if (dmlocalts->ijacobianlocal) {
137:     PetscCall(DMGetLocalVector(dm, &locX));
138:     PetscCall(DMGetLocalVector(dm, &locX_t));
139:     PetscCall(VecZeroEntries(locX));
140:     PetscCall(VecZeroEntries(locX_t));
141:     if (dmlocalts->boundarylocal) PetscCall((*dmlocalts->boundarylocal)(dm, time, locX, locX_t, dmlocalts->boundarylocalctx));
142:     PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX));
143:     PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX));
144:     PetscCall(DMGlobalToLocalBegin(dm, X_t, INSERT_VALUES, locX_t));
145:     PetscCall(DMGlobalToLocalEnd(dm, X_t, INSERT_VALUES, locX_t));
146:     CHKMEMQ;
147:     PetscCall((*dmlocalts->ijacobianlocal)(dm, time, locX, locX_t, a, A, B, dmlocalts->ijacobianlocalctx));
148:     CHKMEMQ;
149:     PetscCall(DMRestoreLocalVector(dm, &locX));
150:     PetscCall(DMRestoreLocalVector(dm, &locX_t));
151:   } else {
152:     MatFDColoring fdcoloring;
153:     PetscCall(PetscObjectQuery((PetscObject)dm, "DMDASNES_FDCOLORING", (PetscObject *)&fdcoloring));
154:     if (!fdcoloring) {
155:       ISColoring coloring;

157:       PetscCall(DMCreateColoring(dm, dm->coloringtype, &coloring));
158:       PetscCall(MatFDColoringCreate(B, coloring, &fdcoloring));
159:       PetscCall(ISColoringDestroy(&coloring));
160:       switch (dm->coloringtype) {
161:       case IS_COLORING_GLOBAL:
162:         PetscCall(MatFDColoringSetFunction(fdcoloring, (MatFDColoringFn *)TSComputeIFunction_DMLocal, dmlocalts));
163:         break;
164:       default:
165:         SETERRQ(PetscObjectComm((PetscObject)ts), PETSC_ERR_SUP, "No support for coloring type '%s'", ISColoringTypes[dm->coloringtype]);
166:       }
167:       PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fdcoloring, ((PetscObject)dm)->prefix));
168:       PetscCall(MatFDColoringSetFromOptions(fdcoloring));
169:       PetscCall(MatFDColoringSetUp(B, coloring, fdcoloring));
170:       PetscCall(PetscObjectCompose((PetscObject)dm, "DMDASNES_FDCOLORING", (PetscObject)fdcoloring));
171:       PetscCall(PetscObjectDereference((PetscObject)fdcoloring));

173:       /* The following breaks an ugly reference counting loop that deserves a paragraph. MatFDColoringApply() will call
174:        * VecDuplicate() with the state Vec and store inside the MatFDColoring. This Vec will duplicate the Vec, but the
175:        * MatFDColoring is composed with the DM. We dereference the DM here so that the reference count will eventually
176:        * drop to 0. Note the code in DMDestroy() that exits early for a negative reference count. That code path will be
177:        * taken when the PetscObjectList for the Vec inside MatFDColoring is destroyed.
178:        */
179:       PetscCall(PetscObjectDereference((PetscObject)dm));
180:     }
181:     PetscCall(MatFDColoringApply(B, fdcoloring, X, ts));
182:   }
183:   /* This will be redundant if the user called both, but it's too common to forget. */
184:   if (A != B) {
185:     PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
186:     PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
187:   }
188:   PetscFunctionReturn(PETSC_SUCCESS);
189: }

191: /*@C
192:   DMTSSetBoundaryLocal - set the function for essential boundary data for a local implicit function evaluation.

194:   Logically Collective

196:   Input Parameters:
197: + dm   - `DM` to associate callback with
198: . func - local function evaluation
199: - ctx  - context for function evaluation

201:   Level: intermediate

203:   Notes:
204:   `func` should set the essential boundary data for the local portion of the solution, as
205:   well its time derivative (if it is not `NULL`).

207:   Vectors are initialized to zero before this function, so it is only needed for non
208:   homogeneous data.

210:   This function is somewhat optional: boundary data could potentially be inserted by a function
211:   passed to `DMTSSetIFunctionLocal()`. The use case for this function is for discretizations
212:   with constraints (see `DMGetDefaultConstraints()`): this function inserts boundary values
213:   before constraint interpolation.

215: .seealso: [](ch_ts), `DM`, `TS`, `DMTSSetIFunction()`, `DMTSSetIJacobianLocal()`
216: @*/
217: PetscErrorCode DMTSSetBoundaryLocal(DM dm, PetscErrorCode (*func)(DM, PetscReal, Vec, Vec, void *), void *ctx)
218: {
219:   DMTS        tdm;
220:   DMTS_Local *dmlocalts;

222:   PetscFunctionBegin;
224:   PetscCall(DMGetDMTSWrite(dm, &tdm));
225:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));

227:   dmlocalts->boundarylocal    = func;
228:   dmlocalts->boundarylocalctx = ctx;
229:   PetscFunctionReturn(PETSC_SUCCESS);
230: }

232: /*@C
233:   DMTSGetIFunctionLocal - get the local implicit function evaluation function. This function is called with local vector
234:   containing the local vector information PLUS ghost point information. It should compute a result for all local
235:   elements and `DM` will automatically accumulate the overlapping values.

237:   Logically Collective

239:   Input Parameter:
240: . dm - `DM` to associate callback with

242:   Output Parameters:
243: + func - local function evaluation
244: - ctx  - context for function evaluation

246:   Level: beginner

248: .seealso: [](ch_ts), `DM`, `DMTSSetIFunctionLocal()`, `DMTSSetIFunction()`, `DMTSSetIJacobianLocal()`
249: @*/
250: PetscErrorCode DMTSGetIFunctionLocal(DM dm, PetscErrorCode (**func)(DM, PetscReal, Vec, Vec, Vec, void *), void **ctx)
251: {
252:   DMTS        tdm;
253:   DMTS_Local *dmlocalts;

255:   PetscFunctionBegin;
257:   PetscCall(DMGetDMTS(dm, &tdm));
258:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));
259:   if (func) {
260:     PetscAssertPointer(func, 2);
261:     *func = dmlocalts->ifunctionlocal;
262:   }
263:   if (ctx) {
264:     PetscAssertPointer(ctx, 3);
265:     *ctx = dmlocalts->ifunctionlocalctx;
266:   }
267:   PetscFunctionReturn(PETSC_SUCCESS);
268: }

270: /*@C
271:   DMTSSetIFunctionLocal - set a local implicit function evaluation function. This function is called with local vector
272:   containing the local vector information PLUS ghost point information. It should compute a result for all local
273:   elements and `DM` will automatically accumulate the overlapping values.

275:   Logically Collective

277:   Input Parameters:
278: + dm   - `DM` to associate callback with
279: . func - local function evaluation
280: - ctx  - context for function evaluation

282:   Level: beginner

284: .seealso: [](ch_ts), `DM`, `DMTSGetIFunctionLocal()`, `DMTSSetIFunction()`, `DMTSSetIJacobianLocal()`
285: @*/
286: PetscErrorCode DMTSSetIFunctionLocal(DM dm, PetscErrorCode (*func)(DM, PetscReal, Vec, Vec, Vec, void *), void *ctx)
287: {
288:   DMTS        tdm;
289:   DMTS_Local *dmlocalts;

291:   PetscFunctionBegin;
293:   PetscCall(DMGetDMTSWrite(dm, &tdm));
294:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));

296:   dmlocalts->ifunctionlocal    = func;
297:   dmlocalts->ifunctionlocalctx = ctx;

299:   PetscCall(DMTSSetIFunction(dm, TSComputeIFunction_DMLocal, dmlocalts));
300:   if (!tdm->ops->ijacobian) { /* Call us for the Jacobian too, can be overridden by the user. */
301:     PetscCall(DMTSSetIJacobian(dm, TSComputeIJacobian_DMLocal, dmlocalts));
302:   }
303:   PetscFunctionReturn(PETSC_SUCCESS);
304: }

306: /*@C
307:   DMTSGetIJacobianLocal - get a local Jacobian evaluation function

309:   Logically Collective

311:   Input Parameter:
312: . dm - `DM` to associate callback with

314:   Output Parameters:
315: + func - local Jacobian evaluation
316: - ctx  - optional context for local Jacobian evaluation

318:   Level: beginner

320: .seealso: [](ch_ts), `DM`, `DMTSSetIJacobianLocal()`, `DMTSSetIFunctionLocal()`, `DMTSSetIJacobian()`, `DMTSSetIFunction()`
321: @*/
322: PetscErrorCode DMTSGetIJacobianLocal(DM dm, PetscErrorCode (**func)(DM, PetscReal, Vec, Vec, PetscReal, Mat, Mat, void *), void **ctx)
323: {
324:   DMTS        tdm;
325:   DMTS_Local *dmlocalts;

327:   PetscFunctionBegin;
329:   PetscCall(DMGetDMTS(dm, &tdm));
330:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));
331:   if (func) {
332:     PetscAssertPointer(func, 2);
333:     *func = dmlocalts->ijacobianlocal;
334:   }
335:   if (ctx) {
336:     PetscAssertPointer(ctx, 3);
337:     *ctx = dmlocalts->ijacobianlocalctx;
338:   }
339:   PetscFunctionReturn(PETSC_SUCCESS);
340: }

342: /*@C
343:   DMTSSetIJacobianLocal - set a local Jacobian evaluation function

345:   Logically Collective

347:   Input Parameters:
348: + dm   - `DM` to associate callback with
349: . func - local Jacobian evaluation
350: - ctx  - optional context for local Jacobian evaluation

352:   Level: beginner

354: .seealso: [](ch_ts), `DM`, `DMTSGetIJacobianLocal()`, `DMTSSetIFunctionLocal()`, `DMTSSetIJacobian()`, `DMTSSetIFunction()`
355: @*/
356: PetscErrorCode DMTSSetIJacobianLocal(DM dm, PetscErrorCode (*func)(DM, PetscReal, Vec, Vec, PetscReal, Mat, Mat, void *), void *ctx)
357: {
358:   DMTS        tdm;
359:   DMTS_Local *dmlocalts;

361:   PetscFunctionBegin;
363:   PetscCall(DMGetDMTSWrite(dm, &tdm));
364:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));

366:   dmlocalts->ijacobianlocal    = func;
367:   dmlocalts->ijacobianlocalctx = ctx;

369:   PetscCall(DMTSSetIJacobian(dm, TSComputeIJacobian_DMLocal, dmlocalts));
370:   PetscFunctionReturn(PETSC_SUCCESS);
371: }

373: /*@C
374:   DMTSGetRHSFunctionLocal - get a local rhs function evaluation function. This function is called with local vector
375:   containing the local vector information PLUS ghost point information. It should compute a result for all local
376:   elements and `DM` will automatically accumulate the overlapping values.

378:   Logically Collective

380:   Input Parameter:
381: . dm - `DM` to associate callback with

383:   Output Parameters:
384: + func - local function evaluation
385: - ctx  - context for function evaluation

387:   Level: beginner

389: .seealso: [](ch_ts), `DM`, `DMTSSetRHSFunctionLocal()`, `DMTSSetRHSFunction()`, `DMTSSetIFunction()`, `DMTSSetIJacobianLocal()`
390: @*/
391: PetscErrorCode DMTSGetRHSFunctionLocal(DM dm, PetscErrorCode (**func)(DM, PetscReal, Vec, Vec, void *), void **ctx)
392: {
393:   DMTS        tdm;
394:   DMTS_Local *dmlocalts;

396:   PetscFunctionBegin;
398:   PetscCall(DMGetDMTS(dm, &tdm));
399:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));
400:   if (func) {
401:     PetscAssertPointer(func, 2);
402:     *func = dmlocalts->rhsfunctionlocal;
403:   }
404:   if (ctx) {
405:     PetscAssertPointer(ctx, 3);
406:     *ctx = dmlocalts->rhsfunctionlocalctx;
407:   }
408:   PetscFunctionReturn(PETSC_SUCCESS);
409: }

411: /*@C
412:   DMTSSetRHSFunctionLocal - set a local rhs function evaluation function. This function is called with local vector
413:   containing the local vector information PLUS ghost point information. It should compute a result for all local
414:   elements and `DM` will automatically accumulate the overlapping values.

416:   Logically Collective

418:   Input Parameters:
419: + dm   - `DM` to associate callback with
420: . func - local function evaluation
421: - ctx  - context for function evaluation

423:   Level: beginner

425: .seealso: [](ch_ts), `DM`, `DMTSGetRHSFunctionLocal()`, `DMTSSetRHSFunction()`, `DMTSSetIFunction()`, `DMTSSetIJacobianLocal()`
426: @*/
427: PetscErrorCode DMTSSetRHSFunctionLocal(DM dm, PetscErrorCode (*func)(DM, PetscReal, Vec, Vec, void *), void *ctx)
428: {
429:   DMTS        tdm;
430:   DMTS_Local *dmlocalts;

432:   PetscFunctionBegin;
434:   PetscCall(DMGetDMTSWrite(dm, &tdm));
435:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));

437:   dmlocalts->rhsfunctionlocal    = func;
438:   dmlocalts->rhsfunctionlocalctx = ctx;

440:   PetscCall(DMTSSetRHSFunction(dm, TSComputeRHSFunction_DMLocal, dmlocalts));
441:   PetscFunctionReturn(PETSC_SUCCESS);
442: }

444: /*@
445:   DMTSCreateRHSMassMatrix - This creates the mass matrix associated with the given `DM`, and a solver to invert it, and stores them in the `DM` context.

447:   Collective

449:   Input Parameter:
450: . dm - `DM` providing the mass matrix

452:   Level: developer

454:   Note:
455:   The idea here is that an explicit system can be given a mass matrix, based on the `DM`, which is inverted on the RHS at each step.

457: .seealso: [](ch_ts), `DM`, `DMTSCreateRHSMassMatrixLumped()`, `DMTSDestroyRHSMassMatrix()`, `DMCreateMassMatrix()`, `DMTS`
458: @*/
459: PetscErrorCode DMTSCreateRHSMassMatrix(DM dm)
460: {
461:   DMTS        tdm;
462:   DMTS_Local *dmlocalts;
463:   const char *prefix;

465:   PetscFunctionBegin;
467:   PetscCall(DMGetDMTSWrite(dm, &tdm));
468:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));
469:   PetscCall(DMCreateMassMatrix(dm, dm, &dmlocalts->mass));
470:   PetscCall(KSPCreate(PetscObjectComm((PetscObject)dm), &dmlocalts->kspmass));
471:   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
472:   PetscCall(KSPSetOptionsPrefix(dmlocalts->kspmass, prefix));
473:   PetscCall(KSPAppendOptionsPrefix(dmlocalts->kspmass, "mass_"));
474:   PetscCall(KSPSetFromOptions(dmlocalts->kspmass));
475:   PetscCall(KSPSetOperators(dmlocalts->kspmass, dmlocalts->mass, dmlocalts->mass));
476:   PetscFunctionReturn(PETSC_SUCCESS);
477: }

479: /*@
480:   DMTSCreateRHSMassMatrixLumped - This creates the lumped mass matrix associated with the given `DM`, and a solver to invert it, and stores them in the `DM` context.

482:   Collective

484:   Input Parameter:
485: . dm - `DM` providing the mass matrix

487:   Level: developer

489:   Note:
490:   The idea here is that an explicit system can be given a mass matrix, based on the `DM`, which is inverted on the RHS at each step.
491:   Since the matrix is lumped, inversion is trivial.

493: .seealso: [](ch_ts), `DM`, `DMTSCreateRHSMassMatrix()`, `DMTSDestroyRHSMassMatrix()`, `DMCreateMassMatrix()`, `DMTS`
494: @*/
495: PetscErrorCode DMTSCreateRHSMassMatrixLumped(DM dm)
496: {
497:   DMTS        tdm;
498:   DMTS_Local *dmlocalts;

500:   PetscFunctionBegin;
502:   PetscCall(DMGetDMTSWrite(dm, &tdm));
503:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));
504:   PetscCall(DMCreateMassMatrixLumped(dm, NULL, &dmlocalts->lumpedmassinv));
505:   PetscCall(VecReciprocal(dmlocalts->lumpedmassinv));
506:   PetscCall(VecViewFromOptions(dmlocalts->lumpedmassinv, NULL, "-lumped_mass_inv_view"));
507:   PetscFunctionReturn(PETSC_SUCCESS);
508: }

510: /*@
511:   DMTSDestroyRHSMassMatrix - Destroys the mass matrix and solver stored in the `DM` context, if they exist.

513:   Logically Collective

515:   Input Parameter:
516: . dm - `DM` providing the mass matrix

518:   Level: developer

520: .seealso: [](ch_ts), `DM`, `DMTSCreateRHSMassMatrixLumped()`, `DMCreateMassMatrix()`, `DMTS`
521: @*/
522: PetscErrorCode DMTSDestroyRHSMassMatrix(DM dm)
523: {
524:   DMTS        tdm;
525:   DMTS_Local *dmlocalts;

527:   PetscFunctionBegin;
529:   PetscCall(DMGetDMTSWrite(dm, &tdm));
530:   PetscCall(DMLocalTSGetContext(dm, tdm, &dmlocalts));
531:   PetscCall(VecDestroy(&dmlocalts->lumpedmassinv));
532:   PetscCall(MatDestroy(&dmlocalts->mass));
533:   PetscCall(KSPDestroy(&dmlocalts->kspmass));
534:   PetscFunctionReturn(PETSC_SUCCESS);
535: }