Date: 2026-07-30T21:14:01+00:00

Actual source code: dmfieldshell.c

      1: #include <petsc/private/dmfieldimpl.h>

      3: typedef struct _n_DMField_Shell {
      4:   PetscCtx ctx;
      5:   PetscErrorCode (*destroy)(DMField);
      6: } DMField_Shell;

      8: /*@
      9:   DMFieldShellGetContext - Retrieve the user-supplied context associated with a `DMFIELDSHELL`.

     11:   Not Collective

     13:   Input Parameter:
     14: . field - the `DMField` of type `DMFIELDSHELL`

     16:   Output Parameter:
     17: . ctx - the context pointer that was passed to `DMFieldCreateShell()`

     19:   Level: intermediate

     21: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldCreateShell()`
     22: @*/
     23: PetscErrorCode DMFieldShellGetContext(DMField field, PetscCtxRt ctx)
     24: {
     25:   PetscBool flg;

     27:   PetscFunctionBegin;
     29:   PetscAssertPointer(ctx, 2);
     30:   PetscCall(PetscObjectTypeCompare((PetscObject)field, DMFIELDSHELL, &flg));
     31:   PetscCheck(flg, PetscObjectComm((PetscObject)field), PETSC_ERR_SUP, "Cannot get context from non-shell shield");
     32:   *(void **)ctx = ((DMField_Shell *)field->data)->ctx;
     33:   PetscFunctionReturn(PETSC_SUCCESS);
     34: }

     36: static PetscErrorCode DMFieldDestroy_Shell(DMField field)
     37: {
     38:   DMField_Shell *shell = (DMField_Shell *)field->data;

     40:   PetscFunctionBegin;
     41:   if (shell->destroy) PetscCall((*shell->destroy)(field));
     42:   PetscCall(PetscFree(field->data));
     43:   PetscFunctionReturn(PETSC_SUCCESS);
     44: }

     46: /*@C
     47:   DMFieldShellEvaluateFEDefault - Default finite-element evaluation for a `DMFIELDSHELL` that maps the quadrature points to real space using the coordinate `DMField` and then calls `DMFieldEvaluate()`.

     49:   Not Collective

     51:   Input Parameters:
     52: + field   - the `DMField` of type `DMFIELDSHELL`
     53: . pointIS - the `IS` of mesh points at which to evaluate
     54: . quad    - the reference-element quadrature
     55: - type    - `PETSC_SCALAR` or `PETSC_REAL`

     57:   Output Parameters:
     58: + B - values at quadrature points, or `NULL`
     59: . D - derivatives at quadrature points, or `NULL`
     60: - H - Hessians at quadrature points, or `NULL`

     62:   Level: developer

     64:   Note:
     65:   Intended to be registered as the FE evaluation callback via `DMFieldShellSetEvaluateFE()` when the shell only supplies a bulk `DMFieldEvaluate()` implementation.

     67: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldShellSetEvaluateFE()`, `DMFieldShellEvaluateFVDefault()`, `DMFieldEvaluate()`
     68: @*/
     69: PetscErrorCode DMFieldShellEvaluateFEDefault(DMField field, IS pointIS, PetscQuadrature quad, PetscDataType type, void *B, void *D, void *H)
     70: {
     71:   DM           dm = field->dm;
     72:   DMField      coordField;
     73:   PetscFEGeom *geom;
     74:   Vec          pushforward;
     75:   PetscInt     dimC, dim, numPoints, Nq, p, Nc;
     76:   PetscScalar *pfArray;

     78:   PetscFunctionBegin;
     79:   Nc = field->numComponents;
     80:   PetscCall(DMGetCoordinateField(dm, &coordField));
     81:   PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, PETSC_FEGEOM_BASIC, &geom));
     82:   PetscCall(DMGetCoordinateDim(dm, &dimC));
     83:   PetscCall(PetscQuadratureGetData(quad, &dim, NULL, &Nq, NULL, NULL));
     84:   PetscCall(ISGetLocalSize(pointIS, &numPoints));
     85:   PetscCall(PetscMalloc1(dimC * Nq * numPoints, &pfArray));
     86:   for (p = 0; p < numPoints * dimC * Nq; p++) pfArray[p] = geom->v[p];
     87:   PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)pointIS), dimC, dimC * Nq * numPoints, PETSC_DETERMINE, pfArray, &pushforward));
     88:   PetscCall(DMFieldEvaluate(field, pushforward, type, B, D, H));
     89:   /* TODO: handle covariant/contravariant pullbacks */
     90:   if (D) {
     91:     if (type == PETSC_SCALAR) {
     92:       PetscScalar *sD = (PetscScalar *)D;
     93:       PetscInt     q;

     95:       for (p = 0; p < numPoints * Nq; p++) {
     96:         for (q = 0; q < Nc; q++) {
     97:           PetscScalar d[3];

     99:           PetscInt i, j;

    101:           for (i = 0; i < dimC; i++) d[i] = sD[(p * Nc + q) * dimC + i];
    102:           for (i = 0; i < dimC; i++) sD[(p * Nc + q) * dimC + i] = 0.;
    103:           for (i = 0; i < dimC; i++) {
    104:             for (j = 0; j < dimC; j++) sD[(p * Nc + q) * dimC + i] += geom->J[(p * dimC + j) * dimC + i] * d[j];
    105:           }
    106:         }
    107:       }
    108:     } else {
    109:       PetscReal *rD = (PetscReal *)D;
    110:       PetscInt   q;

    112:       for (p = 0; p < numPoints * Nq; p++) {
    113:         for (q = 0; q < Nc; q++) {
    114:           PetscReal d[3];

    116:           PetscInt i, j;

    118:           for (i = 0; i < dimC; i++) d[i] = rD[(p * Nc + q) * dimC + i];
    119:           for (i = 0; i < dimC; i++) rD[(p * Nc + q) * dimC + i] = 0.;
    120:           for (i = 0; i < dimC; i++) {
    121:             for (j = 0; j < dimC; j++) rD[(p * Nc + q) * dimC + i] += geom->J[(p * dimC + j) * dimC + i] * d[j];
    122:           }
    123:         }
    124:       }
    125:     }
    126:   }
    127:   if (H) {
    128:     if (type == PETSC_SCALAR) {
    129:       PetscScalar *sH = (PetscScalar *)H;
    130:       PetscInt     q;

    132:       for (p = 0; p < numPoints * Nq; p++) {
    133:         for (q = 0; q < Nc; q++) {
    134:           PetscScalar d[3][3];

    136:           PetscInt i, j, k, l;

    138:           for (i = 0; i < dimC; i++)
    139:             for (j = 0; j < dimC; j++) d[i][j] = sH[((p * Nc + q) * dimC + i) * dimC + j];
    140:           for (i = 0; i < dimC; i++)
    141:             for (j = 0; j < dimC; j++) sH[((p * Nc + q) * dimC + i) * dimC + j] = 0.;
    142:           for (i = 0; i < dimC; i++) {
    143:             for (j = 0; j < dimC; j++) {
    144:               for (k = 0; k < dimC; k++) {
    145:                 for (l = 0; l < dimC; l++) sH[((p * Nc + q) * dimC + i) * dimC + j] += geom->J[(p * dimC + k) * dimC + i] * geom->J[(p * dimC + l) * dimC + j] * d[k][l];
    146:               }
    147:             }
    148:           }
    149:         }
    150:       }
    151:     } else {
    152:       PetscReal *rH = (PetscReal *)H;
    153:       PetscInt   q;

    155:       for (p = 0; p < numPoints * Nq; p++) {
    156:         for (q = 0; q < Nc; q++) {
    157:           PetscReal d[3][3];

    159:           PetscInt i, j, k, l;

    161:           for (i = 0; i < dimC; i++)
    162:             for (j = 0; j < dimC; j++) d[i][j] = rH[((p * Nc + q) * dimC + i) * dimC + j];
    163:           for (i = 0; i < dimC; i++)
    164:             for (j = 0; j < dimC; j++) rH[((p * Nc + q) * dimC + i) * dimC + j] = 0.;
    165:           for (i = 0; i < dimC; i++) {
    166:             for (j = 0; j < dimC; j++) {
    167:               for (k = 0; k < dimC; k++) {
    168:                 for (l = 0; l < dimC; l++) rH[((p * Nc + q) * dimC + i) * dimC + j] += geom->J[(p * dimC + k) * dimC + i] * geom->J[(p * dimC + l) * dimC + j] * d[k][l];
    169:               }
    170:             }
    171:           }
    172:         }
    173:       }
    174:     }
    175:   }
    176:   PetscCall(VecDestroy(&pushforward));
    177:   PetscCall(PetscFree(pfArray));
    178:   PetscCall(PetscFEGeomDestroy(&geom));
    179:   PetscFunctionReturn(PETSC_SUCCESS);
    180: }

    182: /*@C
    183:   DMFieldShellEvaluateFVDefault - Default finite-volume evaluation for a `DMFIELDSHELL` that samples at cell centroids using the coordinate `DMField`'s default quadrature and calls `DMFieldEvaluate()`.

    185:   Not Collective

    187:   Input Parameters:
    188: + field   - the `DMField` of type `DMFIELDSHELL`
    189: . pointIS - the `IS` of mesh cells at which to evaluate
    190: - type    - `PETSC_SCALAR` or `PETSC_REAL`

    192:   Output Parameters:
    193: + B - cell-averaged values, or `NULL`
    194: . D - cell-averaged derivatives, or `NULL`
    195: - H - cell-averaged Hessians, or `NULL`

    197:   Level: developer

    199:   Note:
    200:   Intended to be registered as the FV evaluation callback via `DMFieldShellSetEvaluateFV()` when the shell only supplies a bulk `DMFieldEvaluate()` implementation.

    202: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldShellSetEvaluateFV()`, `DMFieldShellEvaluateFEDefault()`, `DMFieldEvaluate()`
    203: @*/
    204: PetscErrorCode DMFieldShellEvaluateFVDefault(DMField field, IS pointIS, PetscDataType type, void *B, void *D, void *H)
    205: {
    206:   DM              dm = field->dm;
    207:   DMField         coordField;
    208:   PetscFEGeom    *geom;
    209:   Vec             pushforward;
    210:   PetscInt        dimC, dim, numPoints, Nq, p;
    211:   PetscScalar    *pfArray;
    212:   PetscQuadrature quad;
    213:   MPI_Comm        comm;

    215:   PetscFunctionBegin;
    216:   PetscCall(PetscObjectGetComm((PetscObject)field, &comm));
    217:   PetscCall(DMGetDimension(dm, &dim));
    218:   PetscCall(DMGetCoordinateDim(dm, &dimC));
    219:   PetscCall(DMGetCoordinateField(dm, &coordField));
    220:   PetscCall(DMFieldGetFVQuadrature_Internal(coordField, pointIS, &quad));
    221:   PetscCheck(quad, comm, PETSC_ERR_ARG_WRONGSTATE, "coordinate field must have default quadrature for FV computation");
    222:   PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
    223:   PetscCheck(Nq == 1, comm, PETSC_ERR_ARG_WRONGSTATE, "quadrature must have only one point");
    224:   PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, PETSC_FEGEOM_BASIC, &geom));
    225:   PetscCall(ISGetLocalSize(pointIS, &numPoints));
    226:   PetscCall(PetscMalloc1(dimC * numPoints, &pfArray));
    227:   for (p = 0; p < numPoints * dimC; p++) pfArray[p] = geom->v[p];
    228:   PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)pointIS), dimC, dimC * numPoints, PETSC_DETERMINE, pfArray, &pushforward));
    229:   PetscCall(DMFieldEvaluate(field, pushforward, type, B, D, H));
    230:   PetscCall(PetscQuadratureDestroy(&quad));
    231:   PetscCall(VecDestroy(&pushforward));
    232:   PetscCall(PetscFree(pfArray));
    233:   PetscCall(PetscFEGeomDestroy(&geom));
    234:   PetscFunctionReturn(PETSC_SUCCESS);
    235: }

    237: /*@C
    238:   DMFieldShellSetDestroy - Register a destroy callback that will be invoked when a `DMFIELDSHELL` is destroyed.

    240:   Logically Collective

    242:   Input Parameters:
    243: + field   - the `DMField` of type `DMFIELDSHELL`
    244: - destroy - the destroy routine, called before the shell's own data is freed

    246:   Calling sequence of `destroy`:
    247: . field - the `DMField` of type `DMFIELDSHELL` being destroyed

    249:   Level: intermediate

    251: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldCreateShell()`, `DMFieldDestroy()`
    252: @*/
    253: PetscErrorCode DMFieldShellSetDestroy(DMField field, PetscErrorCode (*destroy)(DMField field))
    254: {
    255:   DMField_Shell *shell = (DMField_Shell *)field->data;

    257:   PetscFunctionBegin;
    259:   shell->destroy = destroy;
    260:   PetscFunctionReturn(PETSC_SUCCESS);
    261: }

    263: /*@C
    264:   DMFieldShellSetEvaluate - Register the routine that evaluates a `DMFIELDSHELL` at an arbitrary set of real-space points supplied as a `Vec` of coordinates.

    266:   Logically Collective

    268:   Input Parameters:
    269: + field    - the `DMField` of type `DMFIELDSHELL`
    270: - evaluate - the evaluation callback

    272:   Calling sequence of `evaluate`:
    273: + field - the `DMField` of type `DMFIELDSHELL`
    274: . u     - the points at which to evaluate the field, as a `Vec` of coordinates of size d x n
    275: . dtype - `PETSC_SCALAR` or `PETSC_REAL`
    276: . B     - array of field values at each point, or `NULL`
    277: . D     - array of field spatial derivatives at each point, or `NULL`
    278: - H     - array of field spatial Hessians at each point, or `NULL`

    280:   Level: intermediate

    282: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldCreateShell()`, `DMFieldEvaluate()`, `DMFieldShellSetEvaluateFE()`, `DMFieldShellSetEvaluateFV()`
    283: @*/
    284: PetscErrorCode DMFieldShellSetEvaluate(DMField field, PetscErrorCode (*evaluate)(DMField field, Vec u, PetscDataType dtype, void *B, void *D, void *H))
    285: {
    286:   PetscFunctionBegin;
    288:   field->ops->evaluate = evaluate;
    289:   PetscFunctionReturn(PETSC_SUCCESS);
    290: }

    292: /*@C
    293:   DMFieldShellSetEvaluateFE - Register the routine that evaluates a `DMFIELDSHELL` at finite-element quadrature points over a set of mesh points.

    295:   Logically Collective

    297:   Input Parameters:
    298: + field      - the `DMField` of type `DMFIELDSHELL`
    299: - evaluateFE - the FE evaluation callback

    301:   Calling sequence of `evaluateFE`:
    302: + field - the `DMField` of type `DMFIELDSHELL`
    303: . is    - the `IS` of mesh cells on which to evaluate the field
    304: . quad  - the reference-cell `PetscQuadrature` supplying the evaluation points
    305: . dtype - `PETSC_SCALAR` or `PETSC_REAL`
    306: . B     - array of field values at each quadrature point, or `NULL`
    307: . D     - array of field reference derivatives at each quadrature point, or `NULL`
    308: - H     - array of field reference Hessians at each quadrature point, or `NULL`

    310:   Level: intermediate

    312:   Note:
    313:   If the shell only supplies a generic `DMFieldEvaluate()` via `DMFieldShellSetEvaluate()`, pass `DMFieldShellEvaluateFEDefault()` here.

    315: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldCreateShell()`, `DMFieldEvaluateFE()`, `DMFieldShellEvaluateFEDefault()`, `DMFieldShellSetEvaluateFV()`
    316: @*/
    317: PetscErrorCode DMFieldShellSetEvaluateFE(DMField field, PetscErrorCode (*evaluateFE)(DMField field, IS is, PetscQuadrature quad, PetscDataType dtype, void *B, void *D, void *H))
    318: {
    319:   PetscFunctionBegin;
    321:   field->ops->evaluateFE = evaluateFE;
    322:   PetscFunctionReturn(PETSC_SUCCESS);
    323: }

    325: /*@C
    326:   DMFieldShellSetEvaluateFV - Register the routine that evaluates a `DMFIELDSHELL` as cell averages over a set of mesh cells.

    328:   Logically Collective

    330:   Input Parameters:
    331: + field      - the `DMField` of type `DMFIELDSHELL`
    332: - evaluateFV - the FV evaluation callback

    334:   Calling sequence of `evaluateFV`:
    335: + field - the `DMField` of type `DMFIELDSHELL`
    336: . is    - the `IS` of mesh cells on which to evaluate the field
    337: . dtype - `PETSC_SCALAR` or `PETSC_REAL`
    338: . B     - array of cell-averaged field values, or `NULL`
    339: . D     - array of cell-averaged field derivatives, or `NULL`
    340: - H     - array of cell-averaged field Hessians, or `NULL`

    342:   Level: intermediate

    344:   Note:
    345:   If the shell only supplies a generic `DMFieldEvaluate()` via `DMFieldShellSetEvaluate()`, pass `DMFieldShellEvaluateFVDefault()` here.

    347: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldCreateShell()`, `DMFieldEvaluateFV()`, `DMFieldShellEvaluateFVDefault()`, `DMFieldShellSetEvaluateFE()`
    348: @*/
    349: PetscErrorCode DMFieldShellSetEvaluateFV(DMField field, PetscErrorCode (*evaluateFV)(DMField field, IS is, PetscDataType dtype, void *B, void *D, void *H))
    350: {
    351:   PetscFunctionBegin;
    353:   field->ops->evaluateFV = evaluateFV;
    354:   PetscFunctionReturn(PETSC_SUCCESS);
    355: }

    357: /*@C
    358:   DMFieldShellSetGetDegree - Register the routine that reports the polynomial degree bounds of a `DMFIELDSHELL` over a set of mesh points.

    360:   Logically Collective

    362:   Input Parameters:
    363: + field     - the `DMField` of type `DMFIELDSHELL`
    364: - getDegree - callback that returns the minimum and maximum polynomial degrees of the field over the given point `IS`

    366:   Calling sequence of `getDegree`:
    367: + field     - the `DMField` of type `DMFIELDSHELL`
    368: . is        - the `IS` of mesh points over which the degree bounds are requested
    369: . minDegree - the degree of the largest polynomial space contained in the field on each element
    370: - maxDegree - the largest degree of the smallest polynomial space containing the field on any element

    372:   Level: intermediate

    374: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldCreateShell()`, `DMFieldGetDegree()`
    375: @*/
    376: PetscErrorCode DMFieldShellSetGetDegree(DMField field, PetscErrorCode (*getDegree)(DMField field, IS is, PetscInt *minDegree, PetscInt *maxDegree))
    377: {
    378:   PetscFunctionBegin;
    380:   field->ops->getDegree = getDegree;
    381:   PetscFunctionReturn(PETSC_SUCCESS);
    382: }

    384: /*@C
    385:   DMFieldShellSetCreateDefaultQuadrature - Register the routine that supplies a default `PetscQuadrature` sufficient to integrate a `DMFIELDSHELL` exactly over a set of mesh points.

    387:   Logically Collective

    389:   Input Parameters:
    390: + field  - the `DMField` of type `DMFIELDSHELL`
    391: - create - callback that returns a newly created `PetscQuadrature` for the given point `IS`

    393:   Calling sequence of `create`:
    394: + f    - the `DMField` of type `DMFIELDSHELL`
    395: . is   - the `IS` of mesh points over which the field will be integrated
    396: - quad - the newly created `PetscQuadrature`

    398:   Level: intermediate

    400: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldCreateShell()`, `DMFieldCreateDefaultQuadrature()`
    401: @*/
    402: PetscErrorCode DMFieldShellSetCreateDefaultQuadrature(DMField field, PetscErrorCode (*create)(DMField f, IS is, PetscQuadrature *quad))
    403: {
    404:   PetscFunctionBegin;
    406:   field->ops->createDefaultQuadrature = create;
    407:   PetscFunctionReturn(PETSC_SUCCESS);
    408: }

    410: static PetscErrorCode DMFieldInitialize_Shell(DMField field)
    411: {
    412:   PetscFunctionBegin;
    413:   field->ops->destroy                 = DMFieldDestroy_Shell;
    414:   field->ops->evaluate                = NULL;
    415:   field->ops->evaluateFE              = DMFieldShellEvaluateFEDefault;
    416:   field->ops->evaluateFV              = DMFieldShellEvaluateFVDefault;
    417:   field->ops->getDegree               = NULL;
    418:   field->ops->createDefaultQuadrature = NULL;
    419:   field->ops->view                    = NULL;
    420:   PetscFunctionReturn(PETSC_SUCCESS);
    421: }

    423: PETSC_INTERN PetscErrorCode DMFieldCreate_Shell(DMField field)
    424: {
    425:   DMField_Shell *shell;

    427:   PetscFunctionBegin;
    428:   PetscCall(PetscNew(&shell));
    429:   field->data = shell;
    430:   PetscCall(DMFieldInitialize_Shell(field));
    431:   PetscFunctionReturn(PETSC_SUCCESS);
    432: }

    434: /*@
    435:   DMFieldCreateShell - Create a `DMFIELDSHELL`, a `DMField` whose evaluation is implemented entirely by user-supplied callbacks.

    437:   Collective

    439:   Input Parameters:
    440: + dm            - the `DM` on which the field lives
    441: . numComponents - the number of components of the field
    442: . continuity    - the continuity of the field (e.g. `DMFIELD_VERTEX`)
    443: - ctx           - optional application context returned by `DMFieldShellGetContext()`

    445:   Output Parameter:
    446: . field - the newly created `DMField` of type `DMFIELDSHELL`

    448:   Level: intermediate

    450:   Note:
    451:   After creation the user must register the desired evaluation callbacks with `DMFieldShellSetEvaluate()`, `DMFieldShellSetEvaluateFE()`, `DMFieldShellSetEvaluateFV()`, and optionally `DMFieldShellSetDestroy()`, `DMFieldShellSetGetDegree()`, and `DMFieldShellSetCreateDefaultQuadrature()`.

    453: .seealso: `DMField`, `DMFIELDSHELL`, `DMFieldShellGetContext()`, `DMFieldShellSetEvaluate()`, `DMFieldShellSetEvaluateFE()`, `DMFieldShellSetEvaluateFV()`, `DMFieldShellSetDestroy()`
    454: @*/
    455: PetscErrorCode DMFieldCreateShell(DM dm, PetscInt numComponents, DMFieldContinuity continuity, PetscCtx ctx, DMField *field)
    456: {
    457:   DMField        b;
    458:   DMField_Shell *shell;

    460:   PetscFunctionBegin;
    462:   if (ctx) PetscAssertPointer(ctx, 4);
    463:   PetscAssertPointer(field, 5);
    464:   PetscCall(DMFieldCreate(dm, numComponents, continuity, &b));
    465:   PetscCall(DMFieldSetType(b, DMFIELDSHELL));
    466:   shell      = (DMField_Shell *)b->data;
    467:   shell->ctx = ctx;
    468:   *field     = b;
    469:   PetscFunctionReturn(PETSC_SUCCESS);
    470: }