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 *)(PetscVoidFn *)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: }