Date: 2026-06-01T23:13:17+00:00

Actual source code: petscfeimpl.h

      1: #pragma once

      3: #include <petscfe.h>
      4: #ifdef PETSC_HAVE_LIBCEED
      5: #include <petscfeceed.h>
      6: #endif
      7: #include <petscds.h>
      8: #include <petsc/private/petscimpl.h>
      9: #include <petsc/private/dmpleximpl.h>

     11: PETSC_EXTERN PetscBool      PetscSpaceRegisterAllCalled;
     12: PETSC_EXTERN PetscBool      PetscDualSpaceRegisterAllCalled;
     13: PETSC_EXTERN PetscBool      PetscFERegisterAllCalled;
     14: PETSC_EXTERN PetscErrorCode PetscSpaceRegisterAll(void);
     15: PETSC_EXTERN PetscErrorCode PetscDualSpaceRegisterAll(void);
     16: PETSC_EXTERN PetscErrorCode PetscFERegisterAll(void);

     18: PETSC_INTERN PetscBool  FEcite;
     19: PETSC_INTERN const char FECitation[];

     21: PETSC_EXTERN PetscLogEvent PETSCDUALSPACE_SetUp;
     22: PETSC_EXTERN PetscLogEvent PETSCFE_SetUp;

     24: typedef struct _PetscSpaceOps *PetscSpaceOps;
     25: struct _PetscSpaceOps {
     26:   PetscErrorCode (*setfromoptions)(PetscSpace, PetscOptionItems);
     27:   PetscErrorCode (*setup)(PetscSpace);
     28:   PetscErrorCode (*view)(PetscSpace, PetscViewer);
     29:   PetscErrorCode (*destroy)(PetscSpace);

     31:   PetscErrorCode (*getdimension)(PetscSpace, PetscInt *);
     32:   PetscErrorCode (*evaluate)(PetscSpace, PetscInt, const PetscReal *, PetscReal *, PetscReal *, PetscReal *);
     33:   PetscErrorCode (*getheightsubspace)(PetscSpace, PetscInt, PetscSpace *);
     34: };

     36: struct _p_PetscSpace {
     37:   PETSCHEADER(struct _PetscSpaceOps);
     38:   void    *data;      /* Implementation object */
     39:   PetscInt degree;    /* The approximation order of the space */
     40:   PetscInt maxDegree; /* The containing approximation order of the space */
     41:   PetscInt Nc;        /* The number of components */
     42:   PetscInt Nv;        /* The number of variables in the space, e.g. x and y */
     43:   PetscInt dim;       /* The dimension of the space */
     44:   DM       dm;        /* Shell to use for temp allocation */
     45: };

     47: typedef struct {
     48:   PetscBool   tensor; /* Flag for tensor product */
     49:   PetscBool   setupcalled;
     50:   PetscSpace *subspaces; /* Subspaces for each dimension */
     51: } PetscSpace_Poly;

     53: typedef struct {
     54:   PetscInt    formDegree;
     55:   PetscBool   setupcalled;
     56:   PetscSpace *subspaces;
     57: } PetscSpace_Ptrimmed;

     59: typedef struct {
     60:   PetscSpace *tensspaces;
     61:   PetscInt    numTensSpaces;
     62:   PetscInt    dim;
     63:   PetscBool   uniform;
     64:   PetscBool   setupcalled;
     65:   PetscSpace *heightsubspaces; /* Height subspaces */
     66: } PetscSpace_Tensor;

     68: typedef struct {
     69:   PetscSpace *sumspaces;
     70:   PetscInt    numSumSpaces;
     71:   PetscBool   uniform;
     72:   PetscBool   concatenate;
     73:   PetscBool   setupcalled;
     74:   PetscBool   interleave_basis;
     75:   PetscBool   interleave_components;
     76:   PetscSpace *heightsubspaces; /* Height subspaces */
     77: } PetscSpace_Sum;

     79: typedef struct {
     80:   PetscQuadrature quad; /* The points defining the space */
     81: } PetscSpace_Point;

     83: typedef struct {
     84:   PetscBool setupcalled;
     85: } PetscSpace_WXY;

     87: typedef struct _PetscDualSpaceOps *PetscDualSpaceOps;
     88: struct _PetscDualSpaceOps {
     89:   PetscErrorCode (*setfromoptions)(PetscDualSpace, PetscOptionItems);
     90:   PetscErrorCode (*setup)(PetscDualSpace);
     91:   PetscErrorCode (*view)(PetscDualSpace, PetscViewer);
     92:   PetscErrorCode (*destroy)(PetscDualSpace);

     94:   PetscErrorCode (*duplicate)(PetscDualSpace, PetscDualSpace);
     95:   PetscErrorCode (*createheightsubspace)(PetscDualSpace, PetscInt, PetscDualSpace *);
     96:   PetscErrorCode (*createpointsubspace)(PetscDualSpace, PetscInt, PetscDualSpace *);
     97:   PetscErrorCode (*getsymmetries)(PetscDualSpace, const PetscInt ****, const PetscScalar ****);
     98:   PetscErrorCode (*apply)(PetscDualSpace, PetscInt, PetscReal, PetscFEGeom *, PetscInt, PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *, PetscScalar *);
     99:   PetscErrorCode (*applyall)(PetscDualSpace, const PetscScalar *, PetscScalar *);
    100:   PetscErrorCode (*applyint)(PetscDualSpace, const PetscScalar *, PetscScalar *);
    101:   PetscErrorCode (*createalldata)(PetscDualSpace, PetscQuadrature *, Mat *);
    102:   PetscErrorCode (*createintdata)(PetscDualSpace, PetscQuadrature *, Mat *);
    103: };

    105: struct _p_PetscDualSpace {
    106:   PETSCHEADER(struct _PetscDualSpaceOps);
    107:   void            *data;       /* Implementation object */
    108:   DM               dm;         /* The integration region K */
    109:   PetscInt         order;      /* The approximation order of the space */
    110:   PetscInt         Nc;         /* The number of components */
    111:   PetscQuadrature *functional; /* The basis of functionals for this space */
    112:   Mat              allMat;
    113:   PetscQuadrature  allNodes; /* Collects all quadrature points representing functionals in the basis */
    114:   Vec              allNodeValues;
    115:   Vec              allDofValues;
    116:   Mat              intMat;
    117:   PetscQuadrature  intNodes; /* Collects all quadrature points representing functionals in the basis in the interior of the cell */
    118:   Vec              intNodeValues;
    119:   Vec              intDofValues;
    120:   PetscInt         spdim;    /* The dual-space dimension */
    121:   PetscInt         spintdim; /* The dual-space interior dimension */
    122:   PetscInt         k;        /* k-simplex corresponding to the dofs in this basis (we always use the 3D complex right now) */
    123:   PetscBool        uniform;
    124:   PetscBool        setupcalled;
    125:   PetscBool        setfromoptionscalled;
    126:   PetscSection     pointSection;
    127:   PetscSection     intPointSection;
    128:   PetscDualSpace  *pointSpaces;
    129:   PetscDualSpace  *heightSpaces;
    130:   PetscInt        *numDof;
    131: };

    133: typedef struct _n_Petsc1DNodeFamily   *Petsc1DNodeFamily;
    134: typedef struct _n_PetscLagNodeIndices *PetscLagNodeIndices;

    136: PETSC_EXTERN PetscErrorCode PetscLagNodeIndicesGetData_Internal(PetscLagNodeIndices, PetscInt *, PetscInt *, PetscInt *, const PetscInt *[], const PetscReal *[]);
    137: PETSC_EXTERN PetscErrorCode PetscDualSpaceCreateInteriorSymmetryMatrix_Lagrange(PetscDualSpace sp, PetscInt ornt, Mat *symMat);

    139: typedef struct {
    140:   /* these describe the types of dual spaces implemented */
    141:   PetscBool tensorCell;  /* Flag for tensor product cell */
    142:   PetscBool tensorSpace; /* Flag for tensor product space of polynomials, as opposed to a space of maximum degree */
    143:   PetscBool trimmed;     /* Flag for dual space of trimmed polynomial spaces */
    144:   PetscBool continuous;  /* Flag for a continuous basis, as opposed to discontinuous across element boundaries */

    146:   PetscBool interiorOnly; /* To make setup faster for tensor elements, only construct interior dofs in recursive calls */

    148:   /* these keep track of symmetries */
    149:   PetscInt    ***symperms;
    150:   PetscScalar ***symflips;
    151:   PetscInt       numSelfSym;
    152:   PetscInt       selfSymOff;
    153:   PetscBool      symComputed;

    155:   /* these describe different schemes of placing nodes in a simplex, from
    156:    * which are derived all dofs in Lagrange dual spaces */
    157:   PetscDTNodeType   nodeType;
    158:   PetscBool         endNodes;
    159:   PetscReal         nodeExponent;
    160:   PetscInt          numNodeSkip; /* The number of end nodes from the 1D Node family to skip */
    161:   Petsc1DNodeFamily nodeFamily;

    163:   PetscInt numCopies;

    165:   PetscBool useMoments;  /* Use moments for functionals */
    166:   PetscInt  momentOrder; /* Order for moment quadrature */

    168:   /* these are ways of indexing nodes in a way that makes
    169:    * the computation of symmetries programmatic */
    170:   PetscLagNodeIndices vertIndices;
    171:   PetscLagNodeIndices intNodeIndices;
    172:   PetscLagNodeIndices allNodeIndices;
    173: } PetscDualSpace_Lag;

    175: typedef struct {
    176:   PetscDualSpace         *sumspaces;
    177:   PetscInt                numSumSpaces;
    178:   PetscBool               uniform;
    179:   PetscBool               uniform_all_points;
    180:   PetscBool               uniform_interior_points;
    181:   PetscBool               concatenate;
    182:   PetscBool               setupcalled;
    183:   PetscBool               interleave_basis;
    184:   PetscBool               interleave_components;
    185:   ISLocalToGlobalMapping *all_rows;
    186:   ISLocalToGlobalMapping *all_cols;
    187:   ISLocalToGlobalMapping *int_rows;
    188:   ISLocalToGlobalMapping *int_cols;

    190:   PetscInt    ***symperms;
    191:   PetscScalar ***symflips;
    192:   PetscInt       numSelfSym;
    193:   PetscInt       selfSymOff;
    194:   PetscBool      symComputed;
    195: } PetscDualSpace_Sum;

    197: typedef struct {
    198:   PetscInt  dim;
    199:   PetscInt *numDof;
    200: } PetscDualSpace_Simple;

    202: typedef struct _PetscFEOps *PetscFEOps;
    203: struct _PetscFEOps {
    204:   PetscErrorCode (*setfromoptions)(PetscFE, PetscOptionItems);
    205:   PetscErrorCode (*setup)(PetscFE);
    206:   PetscErrorCode (*view)(PetscFE, PetscViewer);
    207:   PetscErrorCode (*destroy)(PetscFE);
    208:   PetscErrorCode (*getdimension)(PetscFE, PetscInt *);
    209:   PetscErrorCode (*createpointtrace)(PetscFE, PetscInt, PetscFE *);
    210:   PetscErrorCode (*computetabulation)(PetscFE, PetscInt, const PetscReal *, PetscInt, PetscTabulation);
    211:   /* Element integration */
    212:   PetscErrorCode (*integrate)(PetscDS, PetscInt, PetscInt, PetscFEGeom *, const PetscScalar[], PetscDS, const PetscScalar[], PetscScalar[]);
    213:   PetscErrorCode (*integratebd)(PetscDS, PetscInt, PetscBdPointFn *, PetscInt, PetscFEGeom *, const PetscScalar[], PetscDS, const PetscScalar[], PetscScalar[]);
    214:   PetscErrorCode (*integrateresidual)(PetscDS, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscScalar[]);
    215:   PetscErrorCode (*integratebdresidual)(PetscDS, PetscWeakForm, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscScalar[]);
    216:   PetscErrorCode (*integratehybridresidual)(PetscDS, PetscDS, PetscFormKey, PetscInt, PetscInt, PetscFEGeom *, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscScalar[]);
    217:   PetscErrorCode (*integratejacobianaction)(PetscFE, PetscDS, PetscInt, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]);
    218:   PetscErrorCode (*integratejacobian)(PetscDS, PetscDS, PetscFEJacobianType, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]);
    219:   PetscErrorCode (*integratebdjacobian)(PetscDS, PetscWeakForm, PetscFEJacobianType, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]);
    220:   PetscErrorCode (*integratehybridjacobian)(PetscDS, PetscDS, PetscFEJacobianType, PetscFormKey, PetscInt, PetscInt, PetscFEGeom *, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]);
    221: };

    223: struct _p_PetscFE {
    224:   PETSCHEADER(struct _PetscFEOps);
    225:   void           *data;                  /* Implementation object */
    226:   PetscSpace      basisSpace;            /* The basis space P */
    227:   PetscDualSpace  dualSpace;             /* The dual space P' */
    228:   PetscInt        numComponents;         /* The number of field components */
    229:   PetscQuadrature quadrature;            /* Suitable quadrature on K */
    230:   PetscQuadrature faceQuadrature;        /* Suitable face quadrature on \partial K */
    231:   PetscFE        *subspaces;             /* Subspaces for each dimension */
    232:   PetscReal      *invV;                  /* Change of basis matrix, from prime to nodal basis set */
    233:   PetscTabulation T;                     /* Tabulation of basis and derivatives at quadrature points */
    234:   PetscTabulation Tf;                    /* Tabulation of basis and derivatives at quadrature points on each face */
    235:   PetscTabulation Tc;                    /* Tabulation of basis at face centroids */
    236:   PetscInt        blockSize, numBlocks;  /* Blocks are processed concurrently */
    237:   PetscInt        batchSize, numBatches; /* A batch is made up of blocks, Batches are processed in serial */
    238:   PetscBool       setupcalled;
    239: #ifdef PETSC_HAVE_LIBCEED
    240:   Ceed      ceed;      /* The LibCEED context, usually set by the DM */
    241:   CeedBasis ceedBasis; /* Basis for libCEED matching this element */
    242: #endif
    243: };

    245: typedef struct {
    246:   PetscInt cellType;
    247: } PetscFE_Basic;

    249: #ifdef PETSC_HAVE_OPENCL

    251:   #ifdef __APPLE__
    252:     #include <OpenCL/cl.h>
    253:   #else
    254:     #include <CL/cl.h>
    255:   #endif

    257: typedef struct {
    258:   cl_platform_id   pf_id;
    259:   cl_device_id     dev_id;
    260:   cl_context       ctx_id;
    261:   cl_command_queue queue_id;
    262:   PetscDataType    realType;
    263:   PetscLogEvent    residualEvent;
    264:   PetscInt         op; /* ANDY: Stand-in for real equation code generation */
    265: } PetscFE_OpenCL;
    266: #endif

    268: typedef struct {
    269:   PetscInt   numSubelements; /* The number of subelements */
    270:   PetscReal *v0;             /* The affine transformation for each subelement */
    271:   PetscReal *jac, *invjac;
    272:   PetscInt  *embedding; /* Map from subelements dofs to element dofs */
    273: } PetscFE_Composite;

    275: /* Utility functions */
    276: static inline void CoordinatesRefToReal(PetscInt dimReal, PetscInt dimRef, const PetscReal xi0[], const PetscReal v0[], const PetscReal J[], const PetscReal xi[], PetscReal x[])
    277: {
    278:   PetscInt d, e;

    280:   for (d = 0; d < dimReal; ++d) {
    281:     x[d] = v0[d];
    282:     for (e = 0; e < dimRef; ++e) x[d] += J[d * dimReal + e] * (xi[e] - xi0[e]);
    283:   }
    284: }

    286: static inline void CoordinatesRealToRef(PetscInt dimReal, PetscInt dimRef, const PetscReal xi0[], const PetscReal v0[], const PetscReal invJ[], const PetscReal x[], PetscReal xi[])
    287: {
    288:   PetscInt d, e;

    290:   for (d = 0; d < dimRef; ++d) {
    291:     xi[d] = xi0[d];
    292:     for (e = 0; e < dimReal; ++e) xi[d] += invJ[d * dimReal + e] * (x[e] - v0[e]);
    293:   }
    294: }

    296: static inline PetscErrorCode PetscFEInterpolate_Static(PetscFE fe, const PetscScalar x[], PetscFEGeom *fegeom, PetscInt q, PetscScalar interpolant[])
    297: {
    298:   PetscTabulation T;

    300:   PetscFunctionBeginHot;
    301:   PetscCall(PetscFEGetCellTabulation(fe, 0, &T));
    302:   {
    303:     const PetscReal *basis = T->T[0];
    304:     const PetscInt   Nb    = T->Nb;
    305:     const PetscInt   Nc    = T->Nc;
    306:     for (PetscInt fc = 0; fc < Nc; ++fc) {
    307:       interpolant[fc] = 0.0;
    308:       for (PetscInt f = 0; f < Nb; ++f) interpolant[fc] += x[f] * basis[(q * Nb + f) * Nc + fc];
    309:     }
    310:   }
    311:   PetscCall(PetscFEPushforward(fe, fegeom, 1, interpolant));
    312:   PetscFunctionReturn(PETSC_SUCCESS);
    313: }

    315: static inline PetscErrorCode PetscFEInterpolateAtPoints_Static(PetscFE fe, PetscTabulation T, const PetscScalar x[], PetscFEGeom *fegeom, PetscInt q, PetscScalar interpolant[])
    316: {
    317:   PetscInt fc, f;

    319:   PetscFunctionBeginHot;
    320:   {
    321:     const PetscReal *basis = T->T[0];
    322:     const PetscInt   Nb    = T->Nb;
    323:     const PetscInt   Nc    = T->Nc;
    324:     for (fc = 0; fc < Nc; ++fc) {
    325:       interpolant[fc] = 0.0;
    326:       for (f = 0; f < Nb; ++f) interpolant[fc] += x[f] * basis[(q * Nb + f) * Nc + fc];
    327:     }
    328:   }
    329:   PetscCall(PetscFEPushforward(fe, fegeom, 1, interpolant));
    330:   PetscFunctionReturn(PETSC_SUCCESS);
    331: }

    333: static inline PetscErrorCode PetscFEInterpolateGradient_Static(PetscFE fe, PetscInt k, const PetscScalar x[], PetscFEGeom *fegeom, PetscInt q, PetscScalar interpolant[])
    334: {
    335:   PetscTabulation T;
    336:   PetscInt        fc, f, d;

    338:   PetscFunctionBeginHot;
    339:   PetscCall(PetscFEGetCellTabulation(fe, k, &T));
    340:   {
    341:     const PetscReal *basisDer = T->T[1];
    342:     const PetscReal *basisHes = k > 1 ? T->T[2] : NULL;
    343:     const PetscInt   Nb       = T->Nb;
    344:     const PetscInt   Nc       = T->Nc;
    345:     const PetscInt   cdim     = T->cdim;

    347:     PetscCheck(cdim == fegeom->dimEmbed, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Geometry dim %" PetscInt_FMT " must match tabulation dim %" PetscInt_FMT, fegeom->dimEmbed, cdim);
    348:     for (fc = 0; fc < Nc; ++fc) {
    349:       for (d = 0; d < cdim; ++d) interpolant[fc * cdim + d] = 0.0;
    350:       for (f = 0; f < Nb; ++f) {
    351:         for (d = 0; d < cdim; ++d) interpolant[fc * cdim + d] += x[f] * basisDer[((q * Nb + f) * Nc + fc) * cdim + d];
    352:       }
    353:     }
    354:     if (k > 1) {
    355:       const PetscInt off = Nc * cdim;

    357:       for (fc = 0; fc < Nc; ++fc) {
    358:         for (d = 0; d < cdim * cdim; ++d) interpolant[off + fc * cdim * cdim + d] = 0.0;
    359:         for (f = 0; f < Nb; ++f) {
    360:           for (d = 0; d < cdim * cdim; ++d) interpolant[off + fc * cdim + d] += x[f] * basisHes[((q * Nb + f) * Nc + fc) * cdim * cdim + d];
    361:         }
    362:       }
    363:     }
    364:   }
    365:   PetscCall(PetscFEPushforwardGradient(fe, fegeom, 1, interpolant));
    366:   PetscFunctionReturn(PETSC_SUCCESS);
    367: }

    369: static inline PetscErrorCode PetscFEFreeInterpolateGradient_Static(PetscFE fe, const PetscReal basisDer[], const PetscScalar x[], PetscInt dim, const PetscReal invJ[], const PetscReal n[], PetscInt q, PetscScalar interpolant[])
    370: {
    371:   PetscReal   realSpaceDer[3];
    372:   PetscScalar compGradient[3];
    373:   PetscInt    Nb, Nc, fc, f, d, g;

    375:   PetscFunctionBeginHot;
    376:   PetscCall(PetscFEGetDimension(fe, &Nb));
    377:   PetscCall(PetscFEGetNumComponents(fe, &Nc));

    379:   for (fc = 0; fc < Nc; ++fc) {
    380:     interpolant[fc] = 0.0;
    381:     for (d = 0; d < dim; ++d) compGradient[d] = 0.0;
    382:     for (f = 0; f < Nb; ++f) {
    383:       for (d = 0; d < dim; ++d) {
    384:         realSpaceDer[d] = 0.0;
    385:         for (g = 0; g < dim; ++g) realSpaceDer[d] += invJ[g * dim + d] * basisDer[((q * Nb + f) * Nc + fc) * dim + g];
    386:         compGradient[d] += x[f] * realSpaceDer[d];
    387:       }
    388:     }
    389:     if (n) {
    390:       for (d = 0; d < dim; ++d) interpolant[fc] += compGradient[d] * n[d];
    391:     } else {
    392:       for (d = 0; d < dim; ++d) interpolant[d] = compGradient[d];
    393:     }
    394:   }
    395:   PetscFunctionReturn(PETSC_SUCCESS);
    396: }

    398: static inline PetscErrorCode PetscFEInterpolateFieldAndGradient_Static(PetscFE fe, PetscInt k, const PetscScalar x[], PetscFEGeom *fegeom, PetscInt q, PetscScalar interpolant[], PetscScalar interpolantGrad[])
    399: {
    400:   PetscTabulation T;
    401:   PetscInt        fc, f, d;

    403:   PetscFunctionBeginHot;
    404:   PetscCall(PetscFEGetCellTabulation(fe, k, &T));
    405:   {
    406:     const PetscReal *basis    = T->T[0];
    407:     const PetscReal *basisDer = T->T[1];
    408:     const PetscReal *basisHes = k > 1 ? T->T[2] : NULL;
    409:     const PetscInt   Nb       = T->Nb;
    410:     const PetscInt   Nc       = T->Nc;
    411:     const PetscInt   cdim     = T->cdim;

    413:     PetscCheck(cdim == fegeom->dimEmbed, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Geometry dim %" PetscInt_FMT " must match tabulation dim %" PetscInt_FMT, fegeom->dimEmbed, cdim);
    414:     for (fc = 0; fc < Nc; ++fc) {
    415:       interpolant[fc] = 0.0;
    416:       for (d = 0; d < cdim; ++d) interpolantGrad[fc * cdim + d] = 0.0;
    417:       for (f = 0; f < Nb; ++f) {
    418:         interpolant[fc] += x[f] * basis[(q * Nb + f) * Nc + fc];
    419:         for (d = 0; d < cdim; ++d) interpolantGrad[fc * cdim + d] += x[f] * basisDer[((q * Nb + f) * Nc + fc) * cdim + d];
    420:       }
    421:     }
    422:     if (k > 1) {
    423:       const PetscInt off = Nc * cdim;

    425:       for (fc = 0; fc < Nc; ++fc) {
    426:         for (d = 0; d < cdim * cdim; ++d) interpolantGrad[off + fc * cdim * cdim + d] = 0.0;
    427:         for (f = 0; f < Nb; ++f) {
    428:           for (d = 0; d < cdim * cdim; ++d) interpolantGrad[off + fc * cdim + d] += x[f] * basisHes[((q * Nb + f) * Nc + fc) * cdim * cdim + d];
    429:         }
    430:       }
    431:       PetscCall(PetscFEPushforwardHessian(fe, fegeom, 1, &interpolantGrad[off]));
    432:     }
    433:   }
    434:   PetscCall(PetscFEPushforward(fe, fegeom, 1, interpolant));
    435:   PetscCall(PetscFEPushforwardGradient(fe, fegeom, 1, interpolantGrad));
    436:   PetscFunctionReturn(PETSC_SUCCESS);
    437: }

    439: PETSC_INTERN PetscErrorCode PetscDualSpaceLatticePointLexicographic_Internal(PetscInt, PetscInt, PetscInt[]);
    440: PETSC_INTERN PetscErrorCode PetscDualSpaceTensorPointLexicographic_Internal(PetscInt, PetscInt, PetscInt[]);
    441: PETSC_INTERN PetscErrorCode PetscDualSpaceComputeFunctionalsFromAllData(PetscDualSpace);
    442: PETSC_INTERN PetscErrorCode PetscDualSpaceGetBoundarySymmetries_Internal(PetscDualSpace, PetscInt ***, PetscScalar ***);

    444: PETSC_INTERN PetscErrorCode PetscDualSpaceSectionCreate_Internal(PetscDualSpace, PetscSection *);
    445: PETSC_INTERN PetscErrorCode PetscDualSpaceSectionSetUp_Internal(PetscDualSpace, PetscSection);
    446: PETSC_INTERN PetscErrorCode PetscDualSpacePushForwardSubspaces_Internal(PetscDualSpace, PetscInt, PetscInt);

    448: PETSC_INTERN PetscErrorCode PetscFEEvaluateFieldJets_Internal(PetscDS, PetscInt, PetscInt, PetscInt, PetscTabulation[], PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscScalar[], PetscScalar[], PetscScalar[]);
    449: PETSC_INTERN PetscErrorCode PetscFEEvaluateFaceFields_Internal(PetscDS, PetscInt, PetscInt, const PetscScalar[], PetscScalar[]);
    450: PETSC_INTERN PetscErrorCode PetscFEUpdateElementVec_Internal(PetscFE, PetscTabulation, PetscInt, PetscScalar[], PetscScalar[], PetscInt, PetscFEGeom *, PetscScalar[], PetscScalar[], PetscScalar[]);
    451: PETSC_INTERN PetscErrorCode PetscFEUpdateElementMat_Internal(PetscFE, PetscFE, PetscInt, PetscInt, PetscTabulation, PetscScalar[], PetscScalar[], PetscTabulation, PetscScalar[], PetscScalar[], PetscFEGeom *, const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscInt, PetscInt, PetscInt, PetscScalar[]);

    453: PETSC_INTERN PetscErrorCode PetscFEEvaluateFieldJets_Hybrid_Internal(PetscDS, PetscInt, PetscInt, PetscInt, PetscTabulation[], const PetscInt[], const PetscInt[], PetscTabulation[], PetscFEGeom *, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscScalar[], PetscScalar[], PetscScalar[]);
    454: PETSC_INTERN PetscErrorCode PetscFEUpdateElementVec_Hybrid_Internal(PetscFE, PetscTabulation, PetscInt, PetscInt, PetscScalar[], PetscScalar[], PetscFEGeom *, PetscScalar[], PetscScalar[], PetscScalar[]);
    455: PETSC_INTERN PetscErrorCode PetscFEUpdateElementMat_Hybrid_Internal(PetscFE, PetscBool, PetscFE, PetscBool, PetscInt, PetscInt, PetscInt, PetscInt, PetscTabulation, PetscScalar[], PetscScalar[], PetscTabulation, PetscScalar[], PetscScalar[], PetscFEGeom *, const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscInt, PetscInt, PetscInt, PetscInt, PetscScalar[]);

    457: PETSC_INTERN PetscErrorCode PetscFEGetDimension_Basic(PetscFE, PetscInt *);
    458: PETSC_INTERN PetscErrorCode PetscFEIntegrateResidual_Basic(PetscDS, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscScalar[]);
    459: PETSC_INTERN PetscErrorCode PetscFEIntegrateBdResidual_Basic(PetscDS, PetscWeakForm, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscScalar[]);
    460: PETSC_INTERN PetscErrorCode PetscFEIntegrateJacobian_Basic(PetscDS, PetscDS, PetscFEJacobianType, PetscFormKey, PetscInt, PetscFEGeom *, const PetscScalar[], const PetscScalar[], PetscDS, const PetscScalar[], PetscReal, PetscReal, PetscScalar[]);