Actual source code: fe.c
petsc-3.10.5 2019-03-28
Report Typos and Errors

      1: /* Basis Jet Tabulation

      3: We would like to tabulate the nodal basis functions and derivatives at a set of points, usually quadrature points. We
      4: follow here the derviation in http://www.math.ttu.edu/~kirby/papers/fiat-toms-2004.pdf. The nodal basis $\psi_i$ can
      5: be expressed in terms of a prime basis $\phi_i$ which can be stably evaluated. In PETSc, we will use the Legendre basis
      6: as a prime basis.

      8:   \psi_i = \sum_k \alpha_{ki} \phi_k

     10: Our nodal basis is defined in terms of the dual basis $n_j$

     12:   n_j \cdot \psi_i = \delta_{ji}

     14: and we may act on the first equation to obtain

     16:   n_j \cdot \psi_i = \sum_k \alpha_{ki} n_j \cdot \phi_k
     17:        \delta_{ji} = \sum_k \alpha_{ki} V_{jk}
     18:                  I = V \alpha

     20: so the coefficients of the nodal basis in the prime basis are

     22:    \alpha = V^{-1}

     24: We will define the dual basis vectors $n_j$ using a quadrature rule.

     26: Right now, we will just use the polynomial spaces P^k. I know some elements use the space of symmetric polynomials
     27: (I think Nedelec), but we will neglect this for now. Constraints in the space, e.g. Arnold-Winther elements, can
     28: be implemented exactly as in FIAT using functionals $L_j$.

     30: I will have to count the degrees correctly for the Legendre product when we are on simplices.

     32: We will have three objects:
     33:  - Space, P: this just need point evaluation I think
     34:  - Dual Space, P'+K: This looks like a set of functionals that can act on members of P, each n is defined by a Q
     35:  - FEM: This keeps {P, P', Q}
     36: */
     37:  #include <petsc/private/petscfeimpl.h>
     38:  #include <petscdmplex.h>

     40: PetscBool FEcite = PETSC_FALSE;
     41: const char FECitation[] = "@article{kirby2004,\n"
     42:                           "  title   = {Algorithm 839: FIAT, a New Paradigm for Computing Finite Element Basis Functions},\n"
     43:                           "  journal = {ACM Transactions on Mathematical Software},\n"
     44:                           "  author  = {Robert C. Kirby},\n"
     45:                           "  volume  = {30},\n"
     46:                           "  number  = {4},\n"
     47:                           "  pages   = {502--516},\n"
     48:                           "  doi     = {10.1145/1039813.1039820},\n"
     49:                           "  year    = {2004}\n}\n";

     51: PetscClassId PETSCFE_CLASSID = 0;

     53: PetscFunctionList PetscFEList              = NULL;
     54: PetscBool         PetscFERegisterAllCalled = PETSC_FALSE;

     56: /*@C
     57:   PetscFERegister - Adds a new PetscFE implementation

     59:   Not Collective

     61:   Input Parameters:
     62: + name        - The name of a new user-defined creation routine
     63: - create_func - The creation routine itself

     65:   Notes:
     66:   PetscFERegister() may be called multiple times to add several user-defined PetscFEs

     68:   Sample usage:
     69: .vb
     70:     PetscFERegister("my_fe", MyPetscFECreate);
     71: .ve

     73:   Then, your PetscFE type can be chosen with the procedural interface via
     74: .vb
     75:     PetscFECreate(MPI_Comm, PetscFE *);
     76:     PetscFESetType(PetscFE, "my_fe");
     77: .ve
     78:    or at runtime via the option
     79: .vb
     80:     -petscfe_type my_fe
     81: .ve

     83:   Level: advanced

     85: .keywords: PetscFE, register
     86: .seealso: PetscFERegisterAll(), PetscFERegisterDestroy()

     88: @*/
     89: PetscErrorCode PetscFERegister(const char sname[], PetscErrorCode (*function)(PetscFE))
     90: {

     94:   PetscFunctionListAdd(&PetscFEList, sname, function);
     95:   return(0);
     96: }

     98: /*@C
     99:   PetscFESetType - Builds a particular PetscFE

    101:   Collective on PetscFE

    103:   Input Parameters:
    104: + fem  - The PetscFE object
    105: - name - The kind of FEM space

    107:   Options Database Key:
    108: . -petscfe_type <type> - Sets the PetscFE type; use -help for a list of available types

    110:   Level: intermediate

    112: .keywords: PetscFE, set, type
    113: .seealso: PetscFEGetType(), PetscFECreate()
    114: @*/
    115: PetscErrorCode PetscFESetType(PetscFE fem, PetscFEType name)
    116: {
    117:   PetscErrorCode (*r)(PetscFE);
    118:   PetscBool      match;

    123:   PetscObjectTypeCompare((PetscObject) fem, name, &match);
    124:   if (match) return(0);

    126:   if (!PetscFERegisterAllCalled) {PetscFERegisterAll();}
    127:   PetscFunctionListFind(PetscFEList, name, &r);
    128:   if (!r) SETERRQ1(PetscObjectComm((PetscObject) fem), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscFE type: %s", name);

    130:   if (fem->ops->destroy) {
    131:     (*fem->ops->destroy)(fem);
    132:     fem->ops->destroy = NULL;
    133:   }
    134:   (*r)(fem);
    135:   PetscObjectChangeTypeName((PetscObject) fem, name);
    136:   return(0);
    137: }

    139: /*@C
    140:   PetscFEGetType - Gets the PetscFE type name (as a string) from the object.

    142:   Not Collective

    144:   Input Parameter:
    145: . fem  - The PetscFE

    147:   Output Parameter:
    148: . name - The PetscFE type name

    150:   Level: intermediate

    152: .keywords: PetscFE, get, type, name
    153: .seealso: PetscFESetType(), PetscFECreate()
    154: @*/
    155: PetscErrorCode PetscFEGetType(PetscFE fem, PetscFEType *name)
    156: {

    162:   if (!PetscFERegisterAllCalled) {
    163:     PetscFERegisterAll();
    164:   }
    165:   *name = ((PetscObject) fem)->type_name;
    166:   return(0);
    167: }

    169: /*@C
    170:   PetscFEView - Views a PetscFE

    172:   Collective on PetscFE

    174:   Input Parameter:
    175: + fem - the PetscFE object to view
    176: - v   - the viewer

    178:   Level: developer

    180: .seealso PetscFEDestroy()
    181: @*/
    182: PetscErrorCode PetscFEView(PetscFE fem, PetscViewer v)
    183: {

    188:   if (!v) {PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) fem), &v);}
    189:   if (fem->ops->view) {(*fem->ops->view)(fem, v);}
    190:   return(0);
    191: }

    193: /*@
    194:   PetscFESetFromOptions - sets parameters in a PetscFE from the options database

    196:   Collective on PetscFE

    198:   Input Parameter:
    199: . fem - the PetscFE object to set options for

    201:   Options Database:
    202: . -petscfe_num_blocks  the number of cell blocks to integrate concurrently
    203: . -petscfe_num_batches the number of cell batches to integrate serially

    205:   Level: developer

    207: .seealso PetscFEView()
    208: @*/
    209: PetscErrorCode PetscFESetFromOptions(PetscFE fem)
    210: {
    211:   const char    *defaultType;
    212:   char           name[256];
    213:   PetscBool      flg;

    218:   if (!((PetscObject) fem)->type_name) {
    219:     defaultType = PETSCFEBASIC;
    220:   } else {
    221:     defaultType = ((PetscObject) fem)->type_name;
    222:   }
    223:   if (!PetscFERegisterAllCalled) {PetscFERegisterAll();}

    225:   PetscObjectOptionsBegin((PetscObject) fem);
    226:   PetscOptionsFList("-petscfe_type", "Finite element space", "PetscFESetType", PetscFEList, defaultType, name, 256, &flg);
    227:   if (flg) {
    228:     PetscFESetType(fem, name);
    229:   } else if (!((PetscObject) fem)->type_name) {
    230:     PetscFESetType(fem, defaultType);
    231:   }
    232:   PetscOptionsInt("-petscfe_num_blocks", "The number of cell blocks to integrate concurrently", "PetscSpaceSetTileSizes", fem->numBlocks, &fem->numBlocks, NULL);
    233:   PetscOptionsInt("-petscfe_num_batches", "The number of cell batches to integrate serially", "PetscSpaceSetTileSizes", fem->numBatches, &fem->numBatches, NULL);
    234:   if (fem->ops->setfromoptions) {
    235:     (*fem->ops->setfromoptions)(PetscOptionsObject,fem);
    236:   }
    237:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
    238:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) fem);
    239:   PetscOptionsEnd();
    240:   PetscFEViewFromOptions(fem, NULL, "-petscfe_view");
    241:   return(0);
    242: }

    244: /*@C
    245:   PetscFESetUp - Construct data structures for the PetscFE

    247:   Collective on PetscFE

    249:   Input Parameter:
    250: . fem - the PetscFE object to setup

    252:   Level: developer

    254: .seealso PetscFEView(), PetscFEDestroy()
    255: @*/
    256: PetscErrorCode PetscFESetUp(PetscFE fem)
    257: {

    262:   if (fem->setupcalled) return(0);
    263:   fem->setupcalled = PETSC_TRUE;
    264:   if (fem->ops->setup) {(*fem->ops->setup)(fem);}
    265:   return(0);
    266: }

    268: /*@
    269:   PetscFEDestroy - Destroys a PetscFE object

    271:   Collective on PetscFE

    273:   Input Parameter:
    274: . fem - the PetscFE object to destroy

    276:   Level: developer

    278: .seealso PetscFEView()
    279: @*/
    280: PetscErrorCode PetscFEDestroy(PetscFE *fem)
    281: {

    285:   if (!*fem) return(0);

    288:   if (--((PetscObject)(*fem))->refct > 0) {*fem = 0; return(0);}
    289:   ((PetscObject) (*fem))->refct = 0;

    291:   if ((*fem)->subspaces) {
    292:     PetscInt dim, d;

    294:     PetscDualSpaceGetDimension((*fem)->dualSpace, &dim);
    295:     for (d = 0; d < dim; ++d) {PetscFEDestroy(&(*fem)->subspaces[d]);}
    296:   }
    297:   PetscFree((*fem)->subspaces);
    298:   PetscFree((*fem)->invV);
    299:   PetscFERestoreTabulation((*fem), 0, NULL, &(*fem)->B, &(*fem)->D, NULL /*&(*fem)->H*/);
    300:   PetscFERestoreTabulation((*fem), 0, NULL, &(*fem)->Bf, &(*fem)->Df, NULL /*&(*fem)->Hf*/);
    301:   PetscFERestoreTabulation((*fem), 0, NULL, &(*fem)->F, NULL, NULL);
    302:   PetscSpaceDestroy(&(*fem)->basisSpace);
    303:   PetscDualSpaceDestroy(&(*fem)->dualSpace);
    304:   PetscQuadratureDestroy(&(*fem)->quadrature);
    305:   PetscQuadratureDestroy(&(*fem)->faceQuadrature);

    307:   if ((*fem)->ops->destroy) {(*(*fem)->ops->destroy)(*fem);}
    308:   PetscHeaderDestroy(fem);
    309:   return(0);
    310: }

    312: /*@
    313:   PetscFECreate - Creates an empty PetscFE object. The type can then be set with PetscFESetType().

    315:   Collective on MPI_Comm

    317:   Input Parameter:
    318: . comm - The communicator for the PetscFE object

    320:   Output Parameter:
    321: . fem - The PetscFE object

    323:   Level: beginner

    325: .seealso: PetscFESetType(), PETSCFEGALERKIN
    326: @*/
    327: PetscErrorCode PetscFECreate(MPI_Comm comm, PetscFE *fem)
    328: {
    329:   PetscFE        f;

    334:   PetscCitationsRegister(FECitation,&FEcite);
    335:   *fem = NULL;
    336:   PetscFEInitializePackage();

    338:   PetscHeaderCreate(f, PETSCFE_CLASSID, "PetscFE", "Finite Element", "PetscFE", comm, PetscFEDestroy, PetscFEView);

    340:   f->basisSpace    = NULL;
    341:   f->dualSpace     = NULL;
    342:   f->numComponents = 1;
    343:   f->subspaces     = NULL;
    344:   f->invV          = NULL;
    345:   f->B             = NULL;
    346:   f->D             = NULL;
    347:   f->H             = NULL;
    348:   f->Bf            = NULL;
    349:   f->Df            = NULL;
    350:   f->Hf            = NULL;
    351:   PetscMemzero(&f->quadrature, sizeof(PetscQuadrature));
    352:   PetscMemzero(&f->faceQuadrature, sizeof(PetscQuadrature));
    353:   f->blockSize     = 0;
    354:   f->numBlocks     = 1;
    355:   f->batchSize     = 0;
    356:   f->numBatches    = 1;

    358:   *fem = f;
    359:   return(0);
    360: }

    362: /*@
    363:   PetscFEGetSpatialDimension - Returns the spatial dimension of the element

    365:   Not collective

    367:   Input Parameter:
    368: . fem - The PetscFE object

    370:   Output Parameter:
    371: . dim - The spatial dimension

    373:   Level: intermediate

    375: .seealso: PetscFECreate()
    376: @*/
    377: PetscErrorCode PetscFEGetSpatialDimension(PetscFE fem, PetscInt *dim)
    378: {
    379:   DM             dm;

    385:   PetscDualSpaceGetDM(fem->dualSpace, &dm);
    386:   DMGetDimension(dm, dim);
    387:   return(0);
    388: }

    390: /*@
    391:   PetscFESetNumComponents - Sets the number of components in the element

    393:   Not collective

    395:   Input Parameters:
    396: + fem - The PetscFE object
    397: - comp - The number of field components

    399:   Level: intermediate

    401: .seealso: PetscFECreate()
    402: @*/
    403: PetscErrorCode PetscFESetNumComponents(PetscFE fem, PetscInt comp)
    404: {
    407:   fem->numComponents = comp;
    408:   return(0);
    409: }

    411: /*@
    412:   PetscFEGetNumComponents - Returns the number of components in the element

    414:   Not collective

    416:   Input Parameter:
    417: . fem - The PetscFE object

    419:   Output Parameter:
    420: . comp - The number of field components

    422:   Level: intermediate

    424: .seealso: PetscFECreate()
    425: @*/
    426: PetscErrorCode PetscFEGetNumComponents(PetscFE fem, PetscInt *comp)
    427: {
    431:   *comp = fem->numComponents;
    432:   return(0);
    433: }

    435: /*@
    436:   PetscFESetTileSizes - Sets the tile sizes for evaluation

    438:   Not collective

    440:   Input Parameters:
    441: + fem - The PetscFE object
    442: . blockSize - The number of elements in a block
    443: . numBlocks - The number of blocks in a batch
    444: . batchSize - The number of elements in a batch
    445: - numBatches - The number of batches in a chunk

    447:   Level: intermediate

    449: .seealso: PetscFECreate()
    450: @*/
    451: PetscErrorCode PetscFESetTileSizes(PetscFE fem, PetscInt blockSize, PetscInt numBlocks, PetscInt batchSize, PetscInt numBatches)
    452: {
    455:   fem->blockSize  = blockSize;
    456:   fem->numBlocks  = numBlocks;
    457:   fem->batchSize  = batchSize;
    458:   fem->numBatches = numBatches;
    459:   return(0);
    460: }

    462: /*@
    463:   PetscFEGetTileSizes - Returns the tile sizes for evaluation

    465:   Not collective

    467:   Input Parameter:
    468: . fem - The PetscFE object

    470:   Output Parameters:
    471: + blockSize - The number of elements in a block
    472: . numBlocks - The number of blocks in a batch
    473: . batchSize - The number of elements in a batch
    474: - numBatches - The number of batches in a chunk

    476:   Level: intermediate

    478: .seealso: PetscFECreate()
    479: @*/
    480: PetscErrorCode PetscFEGetTileSizes(PetscFE fem, PetscInt *blockSize, PetscInt *numBlocks, PetscInt *batchSize, PetscInt *numBatches)
    481: {
    488:   if (blockSize)  *blockSize  = fem->blockSize;
    489:   if (numBlocks)  *numBlocks  = fem->numBlocks;
    490:   if (batchSize)  *batchSize  = fem->batchSize;
    491:   if (numBatches) *numBatches = fem->numBatches;
    492:   return(0);
    493: }

    495: /*@
    496:   PetscFEGetBasisSpace - Returns the PetscSpace used for approximation of the solution

    498:   Not collective

    500:   Input Parameter:
    501: . fem - The PetscFE object

    503:   Output Parameter:
    504: . sp - The PetscSpace object

    506:   Level: intermediate

    508: .seealso: PetscFECreate()
    509: @*/
    510: PetscErrorCode PetscFEGetBasisSpace(PetscFE fem, PetscSpace *sp)
    511: {
    515:   *sp = fem->basisSpace;
    516:   return(0);
    517: }

    519: /*@
    520:   PetscFESetBasisSpace - Sets the PetscSpace used for approximation of the solution

    522:   Not collective

    524:   Input Parameters:
    525: + fem - The PetscFE object
    526: - sp - The PetscSpace object

    528:   Level: intermediate

    530: .seealso: PetscFECreate()
    531: @*/
    532: PetscErrorCode PetscFESetBasisSpace(PetscFE fem, PetscSpace sp)
    533: {

    539:   PetscSpaceDestroy(&fem->basisSpace);
    540:   fem->basisSpace = sp;
    541:   PetscObjectReference((PetscObject) fem->basisSpace);
    542:   return(0);
    543: }

    545: /*@
    546:   PetscFEGetDualSpace - Returns the PetscDualSpace used to define the inner product

    548:   Not collective

    550:   Input Parameter:
    551: . fem - The PetscFE object

    553:   Output Parameter:
    554: . sp - The PetscDualSpace object

    556:   Level: intermediate

    558: .seealso: PetscFECreate()
    559: @*/
    560: PetscErrorCode PetscFEGetDualSpace(PetscFE fem, PetscDualSpace *sp)
    561: {
    565:   *sp = fem->dualSpace;
    566:   return(0);
    567: }

    569: /*@
    570:   PetscFESetDualSpace - Sets the PetscDualSpace used to define the inner product

    572:   Not collective

    574:   Input Parameters:
    575: + fem - The PetscFE object
    576: - sp - The PetscDualSpace object

    578:   Level: intermediate

    580: .seealso: PetscFECreate()
    581: @*/
    582: PetscErrorCode PetscFESetDualSpace(PetscFE fem, PetscDualSpace sp)
    583: {

    589:   PetscDualSpaceDestroy(&fem->dualSpace);
    590:   fem->dualSpace = sp;
    591:   PetscObjectReference((PetscObject) fem->dualSpace);
    592:   return(0);
    593: }

    595: /*@
    596:   PetscFEGetQuadrature - Returns the PetscQuadrature used to calculate inner products

    598:   Not collective

    600:   Input Parameter:
    601: . fem - The PetscFE object

    603:   Output Parameter:
    604: . q - The PetscQuadrature object

    606:   Level: intermediate

    608: .seealso: PetscFECreate()
    609: @*/
    610: PetscErrorCode PetscFEGetQuadrature(PetscFE fem, PetscQuadrature *q)
    611: {
    615:   *q = fem->quadrature;
    616:   return(0);
    617: }

    619: /*@
    620:   PetscFESetQuadrature - Sets the PetscQuadrature used to calculate inner products

    622:   Not collective

    624:   Input Parameters:
    625: + fem - The PetscFE object
    626: - q - The PetscQuadrature object

    628:   Level: intermediate

    630: .seealso: PetscFECreate()
    631: @*/
    632: PetscErrorCode PetscFESetQuadrature(PetscFE fem, PetscQuadrature q)
    633: {
    634:   PetscInt       Nc, qNc;

    639:   PetscFEGetNumComponents(fem, &Nc);
    640:   PetscQuadratureGetNumComponents(q, &qNc);
    641:   if ((qNc != 1) && (Nc != qNc)) SETERRQ2(PetscObjectComm((PetscObject) fem), PETSC_ERR_ARG_SIZ, "FE components %D != Quadrature components %D and non-scalar quadrature", Nc, qNc);
    642:   PetscFERestoreTabulation(fem, 0, NULL, &fem->B, &fem->D, NULL /*&(*fem)->H*/);
    643:   PetscQuadratureDestroy(&fem->quadrature);
    644:   fem->quadrature = q;
    645:   PetscObjectReference((PetscObject) q);
    646:   return(0);
    647: }

    649: /*@
    650:   PetscFEGetFaceQuadrature - Returns the PetscQuadrature used to calculate inner products on faces

    652:   Not collective

    654:   Input Parameter:
    655: . fem - The PetscFE object

    657:   Output Parameter:
    658: . q - The PetscQuadrature object

    660:   Level: intermediate

    662: .seealso: PetscFECreate()
    663: @*/
    664: PetscErrorCode PetscFEGetFaceQuadrature(PetscFE fem, PetscQuadrature *q)
    665: {
    669:   *q = fem->faceQuadrature;
    670:   return(0);
    671: }

    673: /*@
    674:   PetscFESetFaceQuadrature - Sets the PetscQuadrature used to calculate inner products on faces

    676:   Not collective

    678:   Input Parameters:
    679: + fem - The PetscFE object
    680: - q - The PetscQuadrature object

    682:   Level: intermediate

    684: .seealso: PetscFECreate()
    685: @*/
    686: PetscErrorCode PetscFESetFaceQuadrature(PetscFE fem, PetscQuadrature q)
    687: {

    692:   PetscFERestoreTabulation(fem, 0, NULL, &fem->Bf, &fem->Df, NULL /*&(*fem)->Hf*/);
    693:   PetscQuadratureDestroy(&fem->faceQuadrature);
    694:   fem->faceQuadrature = q;
    695:   PetscObjectReference((PetscObject) q);
    696:   return(0);
    697: }

    699: /*@C
    700:   PetscFEGetNumDof - Returns the number of dofs (dual basis vectors) associated to mesh points on the reference cell of a given dimension

    702:   Not collective

    704:   Input Parameter:
    705: . fem - The PetscFE object

    707:   Output Parameter:
    708: . numDof - Array with the number of dofs per dimension

    710:   Level: intermediate

    712: .seealso: PetscFECreate()
    713: @*/
    714: PetscErrorCode PetscFEGetNumDof(PetscFE fem, const PetscInt **numDof)
    715: {

    721:   PetscDualSpaceGetNumDof(fem->dualSpace, numDof);
    722:   return(0);
    723: }

    725: /*@C
    726:   PetscFEGetDefaultTabulation - Returns the tabulation of the basis functions at the quadrature points

    728:   Not collective

    730:   Input Parameter:
    731: . fem - The PetscFE object

    733:   Output Parameters:
    734: + B - The basis function values at quadrature points
    735: . D - The basis function derivatives at quadrature points
    736: - H - The basis function second derivatives at quadrature points

    738:   Note:
    739: $ B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c
    740: $ D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d
    741: $ H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e

    743:   Level: intermediate

    745: .seealso: PetscFEGetTabulation(), PetscFERestoreTabulation()
    746: @*/
    747: PetscErrorCode PetscFEGetDefaultTabulation(PetscFE fem, PetscReal **B, PetscReal **D, PetscReal **H)
    748: {
    749:   PetscInt         npoints;
    750:   const PetscReal *points;
    751:   PetscErrorCode   ierr;

    758:   PetscQuadratureGetData(fem->quadrature, NULL, NULL, &npoints, &points, NULL);
    759:   if (!fem->B) {PetscFEGetTabulation(fem, npoints, points, &fem->B, &fem->D, NULL/*&fem->H*/);}
    760:   if (B) *B = fem->B;
    761:   if (D) *D = fem->D;
    762:   if (H) *H = fem->H;
    763:   return(0);
    764: }

    766: PetscErrorCode PetscFEGetFaceTabulation(PetscFE fem, PetscReal **Bf, PetscReal **Df, PetscReal **Hf)
    767: {
    768:   PetscErrorCode   ierr;

    775:   if (!fem->Bf) {
    776:     const PetscReal  xi0[3] = {-1., -1., -1.};
    777:     PetscReal        v0[3], J[9], detJ;
    778:     PetscQuadrature  fq;
    779:     PetscDualSpace   sp;
    780:     DM               dm;
    781:     const PetscInt  *faces;
    782:     PetscInt         dim, numFaces, f, npoints, q;
    783:     const PetscReal *points;
    784:     PetscReal       *facePoints;

    786:     PetscFEGetDualSpace(fem, &sp);
    787:     PetscDualSpaceGetDM(sp, &dm);
    788:     DMGetDimension(dm, &dim);
    789:     DMPlexGetConeSize(dm, 0, &numFaces);
    790:     DMPlexGetCone(dm, 0, &faces);
    791:     PetscFEGetFaceQuadrature(fem, &fq);
    792:     if (fq) {
    793:       PetscQuadratureGetData(fq, NULL, NULL, &npoints, &points, NULL);
    794:       PetscMalloc1(numFaces*npoints*dim, &facePoints);
    795:       for (f = 0; f < numFaces; ++f) {
    796:         DMPlexComputeCellGeometryFEM(dm, faces[f], NULL, v0, J, NULL, &detJ);
    797:         for (q = 0; q < npoints; ++q) CoordinatesRefToReal(dim, dim-1, xi0, v0, J, &points[q*(dim-1)], &facePoints[(f*npoints+q)*dim]);
    798:       }
    799:       PetscFEGetTabulation(fem, numFaces*npoints, facePoints, &fem->Bf, &fem->Df, NULL/*&fem->Hf*/);
    800:       PetscFree(facePoints);
    801:     }
    802:   }
    803:   if (Bf) *Bf = fem->Bf;
    804:   if (Df) *Df = fem->Df;
    805:   if (Hf) *Hf = fem->Hf;
    806:   return(0);
    807: }

    809: PetscErrorCode PetscFEGetFaceCentroidTabulation(PetscFE fem, PetscReal **F)
    810: {
    811:   PetscErrorCode   ierr;

    816:   if (!fem->F) {
    817:     PetscDualSpace  sp;
    818:     DM              dm;
    819:     const PetscInt *cone;
    820:     PetscReal      *centroids;
    821:     PetscInt        dim, numFaces, f;

    823:     PetscFEGetDualSpace(fem, &sp);
    824:     PetscDualSpaceGetDM(sp, &dm);
    825:     DMGetDimension(dm, &dim);
    826:     DMPlexGetConeSize(dm, 0, &numFaces);
    827:     DMPlexGetCone(dm, 0, &cone);
    828:     PetscMalloc1(numFaces*dim, &centroids);
    829:     for (f = 0; f < numFaces; ++f) {DMPlexComputeCellGeometryFVM(dm, cone[f], NULL, &centroids[f*dim], NULL);}
    830:     PetscFEGetTabulation(fem, numFaces, centroids, &fem->F, NULL, NULL);
    831:     PetscFree(centroids);
    832:   }
    833:   *F = fem->F;
    834:   return(0);
    835: }

    837: /*@C
    838:   PetscFEGetTabulation - Tabulates the basis functions, and perhaps derivatives, at the points provided.

    840:   Not collective

    842:   Input Parameters:
    843: + fem     - The PetscFE object
    844: . npoints - The number of tabulation points
    845: - points  - The tabulation point coordinates

    847:   Output Parameters:
    848: + B - The basis function values at tabulation points
    849: . D - The basis function derivatives at tabulation points
    850: - H - The basis function second derivatives at tabulation points

    852:   Note:
    853: $ B[(p*pdim + i)*Nc + c] is the value at point p for basis function i and component c
    854: $ D[((p*pdim + i)*Nc + c)*dim + d] is the derivative value at point p for basis function i, component c, in direction d
    855: $ H[(((p*pdim + i)*Nc + c)*dim + d)*dim + e] is the value at point p for basis function i, component c, in directions d and e

    857:   Level: intermediate

    859: .seealso: PetscFERestoreTabulation(), PetscFEGetDefaultTabulation()
    860: @*/
    861: PetscErrorCode PetscFEGetTabulation(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscReal **B, PetscReal **D, PetscReal **H)
    862: {
    863:   DM               dm;
    864:   PetscInt         pdim; /* Dimension of FE space P */
    865:   PetscInt         dim;  /* Spatial dimension */
    866:   PetscInt         comp; /* Field components */
    867:   PetscErrorCode   ierr;

    870:   if (!npoints) {
    871:     if (B) *B = NULL;
    872:     if (D) *D = NULL;
    873:     if (H) *H = NULL;
    874:     return(0);
    875:   }
    881:   PetscDualSpaceGetDM(fem->dualSpace, &dm);
    882:   DMGetDimension(dm, &dim);
    883:   PetscDualSpaceGetDimension(fem->dualSpace, &pdim);
    884:   PetscFEGetNumComponents(fem, &comp);
    885:   if (B) {DMGetWorkArray(dm, npoints*pdim*comp, MPIU_REAL, B);}
    886:   if (!dim) {
    887:     if (D) *D = NULL;
    888:     if (H) *H = NULL;
    889:   } else {
    890:     if (D) {DMGetWorkArray(dm, npoints*pdim*comp*dim, MPIU_REAL, D);}
    891:     if (H) {DMGetWorkArray(dm, npoints*pdim*comp*dim*dim, MPIU_REAL, H);}
    892:   }
    893:   (*fem->ops->gettabulation)(fem, npoints, points, B ? *B : NULL, D ? *D : NULL, H ? *H : NULL);
    894:   return(0);
    895: }

    897: PetscErrorCode PetscFERestoreTabulation(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscReal **B, PetscReal **D, PetscReal **H)
    898: {
    899:   DM             dm;

    904:   PetscDualSpaceGetDM(fem->dualSpace, &dm);
    905:   if (B && *B) {DMRestoreWorkArray(dm, 0, MPIU_REAL, B);}
    906:   if (D && *D) {DMRestoreWorkArray(dm, 0, MPIU_REAL, D);}
    907:   if (H && *H) {DMRestoreWorkArray(dm, 0, MPIU_REAL, H);}
    908:   return(0);
    909: }

    911: PETSC_EXTERN PetscErrorCode PetscFECreatePointTrace(PetscFE fe, PetscInt refPoint, PetscFE *trFE)
    912: {
    913:   PetscSpace     bsp, bsubsp;
    914:   PetscDualSpace dsp, dsubsp;
    915:   PetscInt       dim, depth, numComp, i, j, coneSize, order;
    916:   PetscFEType    type;
    917:   DM             dm;
    918:   DMLabel        label;
    919:   PetscReal      *xi, *v, *J, detJ;
    920:   PetscQuadrature origin, fullQuad, subQuad;

    926:   PetscFEGetBasisSpace(fe,&bsp);
    927:   PetscFEGetDualSpace(fe,&dsp);
    928:   PetscDualSpaceGetDM(dsp,&dm);
    929:   DMGetDimension(dm,&dim);
    930:   DMPlexGetDepthLabel(dm,&label);
    931:   DMLabelGetValue(label,refPoint,&depth);
    932:   PetscCalloc1(depth,&xi);
    933:   PetscMalloc1(dim,&v);
    934:   PetscMalloc1(dim*dim,&J);
    935:   for (i = 0; i < depth; i++) xi[i] = 0.;
    936:   PetscQuadratureCreate(PETSC_COMM_SELF,&origin);
    937:   PetscQuadratureSetData(origin,depth,0,1,xi,NULL);
    938:   DMPlexComputeCellGeometryFEM(dm,refPoint,origin,v,J,NULL,&detJ);
    939:   /* CellGeometryFEM computes the expanded Jacobian, we want the true jacobian */
    940:   for (i = 1; i < dim; i++) {
    941:     for (j = 0; j < depth; j++) {
    942:       J[i * depth + j] = J[i * dim + j];
    943:     }
    944:   }
    945:   PetscQuadratureDestroy(&origin);
    946:   PetscDualSpaceGetPointSubspace(dsp,refPoint,&dsubsp);
    947:   PetscSpaceCreateSubspace(bsp,dsubsp,v,J,NULL,NULL,PETSC_OWN_POINTER,&bsubsp);
    948:   PetscSpaceSetUp(bsubsp);
    949:   PetscFECreate(PetscObjectComm((PetscObject)fe),trFE);
    950:   PetscFEGetType(fe,&type);
    951:   PetscFESetType(*trFE,type);
    952:   PetscFEGetNumComponents(fe,&numComp);
    953:   PetscFESetNumComponents(*trFE,numComp);
    954:   PetscFESetBasisSpace(*trFE,bsubsp);
    955:   PetscFESetDualSpace(*trFE,dsubsp);
    956:   PetscFEGetQuadrature(fe,&fullQuad);
    957:   PetscQuadratureGetOrder(fullQuad,&order);
    958:   DMPlexGetConeSize(dm,refPoint,&coneSize);
    959:   if (coneSize == 2 * depth) {
    960:     PetscDTGaussTensorQuadrature(depth,1,(order + 1)/2,-1.,1.,&subQuad);
    961:   } else {
    962:     PetscDTGaussJacobiQuadrature(depth,1,(order + 1)/2,-1.,1.,&subQuad);
    963:   }
    964:   PetscFESetQuadrature(*trFE,subQuad);
    965:   PetscFESetUp(*trFE);
    966:   PetscQuadratureDestroy(&subQuad);
    967:   PetscSpaceDestroy(&bsubsp);
    968:   return(0);
    969: }

    971: PetscErrorCode PetscFECreateHeightTrace(PetscFE fe, PetscInt height, PetscFE *trFE)
    972: {
    973:   PetscInt       hStart, hEnd;
    974:   PetscDualSpace dsp;
    975:   DM             dm;

    981:   *trFE = NULL;
    982:   PetscFEGetDualSpace(fe,&dsp);
    983:   PetscDualSpaceGetDM(dsp,&dm);
    984:   DMPlexGetHeightStratum(dm,height,&hStart,&hEnd);
    985:   if (hEnd <= hStart) return(0);
    986:   PetscFECreatePointTrace(fe,hStart,trFE);
    987:   return(0);
    988: }

    991: /*@
    992:   PetscFEGetDimension - Get the dimension of the finite element space on a cell

    994:   Not collective

    996:   Input Parameter:
    997: . fe - The PetscFE

    999:   Output Parameter:
    1000: . dim - The dimension

    1002:   Level: intermediate

    1004: .seealso: PetscFECreate(), PetscSpaceGetDimension(), PetscDualSpaceGetDimension()
    1005: @*/
    1006: PetscErrorCode PetscFEGetDimension(PetscFE fem, PetscInt *dim)
    1007: {

    1013:   if (fem->ops->getdimension) {(*fem->ops->getdimension)(fem, dim);}
    1014:   return(0);
    1015: }

    1017: /*
    1018: Purpose: Compute element vector for chunk of elements

    1020: Input:
    1021:   Sizes:
    1022:      Ne:  number of elements
    1023:      Nf:  number of fields
    1024:      PetscFE
    1025:        dim: spatial dimension
    1026:        Nb:  number of basis functions
    1027:        Nc:  number of field components
    1028:        PetscQuadrature
    1029:          Nq:  number of quadrature points

    1031:   Geometry:
    1032:      PetscFEGeom[Ne] possibly *Nq
    1033:        PetscReal v0s[dim]
    1034:        PetscReal n[dim]
    1035:        PetscReal jacobians[dim*dim]
    1036:        PetscReal jacobianInverses[dim*dim]
    1037:        PetscReal jacobianDeterminants
    1038:   FEM:
    1039:      PetscFE
    1040:        PetscQuadrature
    1041:          PetscReal   quadPoints[Nq*dim]
    1042:          PetscReal   quadWeights[Nq]
    1043:        PetscReal   basis[Nq*Nb*Nc]
    1044:        PetscReal   basisDer[Nq*Nb*Nc*dim]
    1045:      PetscScalar coefficients[Ne*Nb*Nc]
    1046:      PetscScalar elemVec[Ne*Nb*Nc]

    1048:   Problem:
    1049:      PetscInt f: the active field
    1050:      f0, f1

    1052:   Work Space:
    1053:      PetscFE
    1054:        PetscScalar f0[Nq*dim];
    1055:        PetscScalar f1[Nq*dim*dim];
    1056:        PetscScalar u[Nc];
    1057:        PetscScalar gradU[Nc*dim];
    1058:        PetscReal   x[dim];
    1059:        PetscScalar realSpaceDer[dim];

    1061: Purpose: Compute element vector for N_cb batches of elements

    1063: Input:
    1064:   Sizes:
    1065:      N_cb: Number of serial cell batches

    1067:   Geometry:
    1068:      PetscReal v0s[Ne*dim]
    1069:      PetscReal jacobians[Ne*dim*dim]        possibly *Nq
    1070:      PetscReal jacobianInverses[Ne*dim*dim] possibly *Nq
    1071:      PetscReal jacobianDeterminants[Ne]     possibly *Nq
    1072:   FEM:
    1073:      static PetscReal   quadPoints[Nq*dim]
    1074:      static PetscReal   quadWeights[Nq]
    1075:      static PetscReal   basis[Nq*Nb*Nc]
    1076:      static PetscReal   basisDer[Nq*Nb*Nc*dim]
    1077:      PetscScalar coefficients[Ne*Nb*Nc]
    1078:      PetscScalar elemVec[Ne*Nb*Nc]

    1080: ex62.c:
    1081:   PetscErrorCode PetscFEIntegrateResidualBatch(PetscInt Ne, PetscInt numFields, PetscInt field, PetscQuadrature quad[], const PetscScalar coefficients[],
    1082:                                                const PetscReal v0s[], const PetscReal jacobians[], const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[],
    1083:                                                void (*f0_func)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]),
    1084:                                                void (*f1_func)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]), PetscScalar elemVec[])

    1086: ex52.c:
    1087:   PetscErrorCode IntegrateLaplacianBatchCPU(PetscInt Ne, PetscInt Nb, const PetscScalar coefficients[], const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[], PetscInt Nq, const PetscReal quadPoints[], const PetscReal quadWeights[], const PetscReal basisTabulation[], const PetscReal basisDerTabulation[], PetscScalar elemVec[], AppCtx *user)
    1088:   PetscErrorCode IntegrateElasticityBatchCPU(PetscInt Ne, PetscInt Nb, PetscInt Ncomp, const PetscScalar coefficients[], const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[], PetscInt Nq, const PetscReal quadPoints[], const PetscReal quadWeights[], const PetscReal basisTabulation[], const PetscReal basisDerTabulation[], PetscScalar elemVec[], AppCtx *user)

    1090: ex52_integrateElement.cu
    1091: __global__ void integrateElementQuadrature(int N_cb, realType *coefficients, realType *jacobianInverses, realType *jacobianDeterminants, realType *elemVec)

    1093: PETSC_EXTERN PetscErrorCode IntegrateElementBatchGPU(PetscInt spatial_dim, PetscInt Ne, PetscInt Ncb, PetscInt Nbc, PetscInt Nbl, const PetscScalar coefficients[],
    1094:                                                      const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[], PetscScalar elemVec[],
    1095:                                                      PetscLogEvent event, PetscInt debug, PetscInt pde_op)

    1097: ex52_integrateElementOpenCL.c:
    1098: PETSC_EXTERN PetscErrorCode IntegrateElementBatchGPU(PetscInt spatial_dim, PetscInt Ne, PetscInt Ncb, PetscInt Nbc, PetscInt N_bl, const PetscScalar coefficients[],
    1099:                                                      const PetscReal jacobianInverses[], const PetscReal jacobianDeterminants[], PetscScalar elemVec[],
    1100:                                                      PetscLogEvent event, PetscInt debug, PetscInt pde_op)

    1102: __kernel void integrateElementQuadrature(int N_cb, __global float *coefficients, __global float *jacobianInverses, __global float *jacobianDeterminants, __global float *elemVec)
    1103: */

    1105: /*@C
    1106:   PetscFEIntegrate - Produce the integral for the given field for a chunk of elements by quadrature integration

    1108:   Not collective

    1110:   Input Parameters:
    1111: + fem          - The PetscFE object for the field being integrated
    1112: . prob         - The PetscDS specifying the discretizations and continuum functions
    1113: . field        - The field being integrated
    1114: . Ne           - The number of elements in the chunk
    1115: . cgeom        - The cell geometry for each cell in the chunk
    1116: . coefficients - The array of FEM basis coefficients for the elements
    1117: . probAux      - The PetscDS specifying the auxiliary discretizations
    1118: - coefficientsAux - The array of FEM auxiliary basis coefficients for the elements

    1120:   Output Parameter
    1121: . integral     - the integral for this field

    1123:   Level: developer

    1125: .seealso: PetscFEIntegrateResidual()
    1126: @*/
    1127: PetscErrorCode PetscFEIntegrate(PetscFE fem, PetscDS prob, PetscInt field, PetscInt Ne, PetscFEGeom *cgeom,
    1128:                                 const PetscScalar coefficients[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
    1129: {

    1135:   if (fem->ops->integrate) {(*fem->ops->integrate)(fem, prob, field, Ne, cgeom, coefficients, probAux, coefficientsAux, integral);}
    1136:   return(0);
    1137: }

    1139: /*@C
    1140:   PetscFEIntegrateBd - Produce the integral for the given field for a chunk of elements by quadrature integration

    1142:   Not collective

    1144:   Input Parameters:
    1145: + fem          - The PetscFE object for the field being integrated
    1146: . prob         - The PetscDS specifying the discretizations and continuum functions
    1147: . field        - The field being integrated
    1148: . obj_func     - The function to be integrated
    1149: . Ne           - The number of elements in the chunk
    1150: . fgeom        - The face geometry for each face in the chunk
    1151: . coefficients - The array of FEM basis coefficients for the elements
    1152: . probAux      - The PetscDS specifying the auxiliary discretizations
    1153: - coefficientsAux - The array of FEM auxiliary basis coefficients for the elements

    1155:   Output Parameter
    1156: . integral     - the integral for this field

    1158:   Level: developer

    1160: .seealso: PetscFEIntegrateResidual()
    1161: @*/
    1162: PetscErrorCode PetscFEIntegrateBd(PetscFE fem, PetscDS prob, PetscInt field,
    1163:                                   void (*obj_func)(PetscInt, PetscInt, PetscInt,
    1164:                                                    const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    1165:                                                    const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
    1166:                                                    PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
    1167:                                   PetscInt Ne, PetscFEGeom *geom, const PetscScalar coefficients[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
    1168: {

    1174:   if (fem->ops->integratebd) {(*fem->ops->integratebd)(fem, prob, field, obj_func, Ne, geom, coefficients, probAux, coefficientsAux, integral);}
    1175:   return(0);
    1176: }

    1178: /*@C
    1179:   PetscFEIntegrateResidual - Produce the element residual vector for a chunk of elements by quadrature integration

    1181:   Not collective

    1183:   Input Parameters:
    1184: + fem          - The PetscFE object for the field being integrated
    1185: . prob         - The PetscDS specifying the discretizations and continuum functions
    1186: . field        - The field being integrated
    1187: . Ne           - The number of elements in the chunk
    1188: . cgeom        - The cell geometry for each cell in the chunk
    1189: . coefficients - The array of FEM basis coefficients for the elements
    1190: . coefficients_t - The array of FEM basis time derivative coefficients for the elements
    1191: . probAux      - The PetscDS specifying the auxiliary discretizations
    1192: . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
    1193: - t            - The time

    1195:   Output Parameter
    1196: . elemVec      - the element residual vectors from each element

    1198:   Note:
    1199: $ Loop over batch of elements (e):
    1200: $   Loop over quadrature points (q):
    1201: $     Make u_q and gradU_q (loops over fields,Nb,Ncomp) and x_q
    1202: $     Call f_0 and f_1
    1203: $   Loop over element vector entries (f,fc --> i):
    1204: $     elemVec[i] += \psi^{fc}_f(q) f0_{fc}(u, \nabla u) + \nabla\psi^{fc}_f(q) \cdot f1_{fc,df}(u, \nabla u)

    1206:   Level: developer

    1208: .seealso: PetscFEIntegrateResidual()
    1209: @*/
    1210: PetscErrorCode PetscFEIntegrateResidual(PetscFE fem, PetscDS prob, PetscInt field, PetscInt Ne, PetscFEGeom *cgeom,
    1211:                                         const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
    1212: {

    1218:   if (fem->ops->integrateresidual) {(*fem->ops->integrateresidual)(fem, prob, field, Ne, cgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, elemVec);}
    1219:   return(0);
    1220: }

    1222: /*@C
    1223:   PetscFEIntegrateBdResidual - Produce the element residual vector for a chunk of elements by quadrature integration over a boundary

    1225:   Not collective

    1227:   Input Parameters:
    1228: + fem          - The PetscFE object for the field being integrated
    1229: . prob         - The PetscDS specifying the discretizations and continuum functions
    1230: . field        - The field being integrated
    1231: . Ne           - The number of elements in the chunk
    1232: . fgeom        - The face geometry for each cell in the chunk
    1233: . coefficients - The array of FEM basis coefficients for the elements
    1234: . coefficients_t - The array of FEM basis time derivative coefficients for the elements
    1235: . probAux      - The PetscDS specifying the auxiliary discretizations
    1236: . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
    1237: - t            - The time

    1239:   Output Parameter
    1240: . elemVec      - the element residual vectors from each element

    1242:   Level: developer

    1244: .seealso: PetscFEIntegrateResidual()
    1245: @*/
    1246: PetscErrorCode PetscFEIntegrateBdResidual(PetscFE fem, PetscDS prob, PetscInt field, PetscInt Ne, PetscFEGeom *fgeom,
    1247:                                           const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
    1248: {

    1253:   if (fem->ops->integratebdresidual) {(*fem->ops->integratebdresidual)(fem, prob, field, Ne, fgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, elemVec);}
    1254:   return(0);
    1255: }

    1257: /*@C
    1258:   PetscFEIntegrateJacobian - Produce the element Jacobian for a chunk of elements by quadrature integration

    1260:   Not collective

    1262:   Input Parameters:
    1263: + fem          - The PetscFE object for the field being integrated
    1264: . prob         - The PetscDS specifying the discretizations and continuum functions
    1265: . jtype        - The type of matrix pointwise functions that should be used
    1266: . fieldI       - The test field being integrated
    1267: . fieldJ       - The basis field being integrated
    1268: . Ne           - The number of elements in the chunk
    1269: . cgeom        - The cell geometry for each cell in the chunk
    1270: . coefficients - The array of FEM basis coefficients for the elements for the Jacobian evaluation point
    1271: . coefficients_t - The array of FEM basis time derivative coefficients for the elements
    1272: . probAux      - The PetscDS specifying the auxiliary discretizations
    1273: . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
    1274: . t            - The time
    1275: - u_tShift     - A multiplier for the dF/du_t term (as opposed to the dF/du term)

    1277:   Output Parameter
    1278: . elemMat      - the element matrices for the Jacobian from each element

    1280:   Note:
    1281: $ Loop over batch of elements (e):
    1282: $   Loop over element matrix entries (f,fc,g,gc --> i,j):
    1283: $     Loop over quadrature points (q):
    1284: $       Make u_q and gradU_q (loops over fields,Nb,Ncomp)
    1285: $         elemMat[i,j] += \psi^{fc}_f(q) g0_{fc,gc}(u, \nabla u) \phi^{gc}_g(q)
    1286: $                      + \psi^{fc}_f(q) \cdot g1_{fc,gc,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
    1287: $                      + \nabla\psi^{fc}_f(q) \cdot g2_{fc,gc,df}(u, \nabla u) \phi^{gc}_g(q)
    1288: $                      + \nabla\psi^{fc}_f(q) \cdot g3_{fc,gc,df,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
    1289:   Level: developer

    1291: .seealso: PetscFEIntegrateResidual()
    1292: @*/
    1293: PetscErrorCode PetscFEIntegrateJacobian(PetscFE fem, PetscDS prob, PetscFEJacobianType jtype, PetscInt fieldI, PetscInt fieldJ, PetscInt Ne, PetscFEGeom *cgeom,
    1294:                                         const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
    1295: {

    1300:   if (fem->ops->integratejacobian) {(*fem->ops->integratejacobian)(fem, prob, jtype, fieldI, fieldJ, Ne, cgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, u_tshift, elemMat);}
    1301:   return(0);
    1302: }

    1304: /*@C
    1305:   PetscFEIntegrateBdJacobian - Produce the boundary element Jacobian for a chunk of elements by quadrature integration

    1307:   Not collective

    1309:   Input Parameters:
    1310: + fem          = The PetscFE object for the field being integrated
    1311: . prob         - The PetscDS specifying the discretizations and continuum functions
    1312: . fieldI       - The test field being integrated
    1313: . fieldJ       - The basis field being integrated
    1314: . Ne           - The number of elements in the chunk
    1315: . fgeom        - The face geometry for each cell in the chunk
    1316: . coefficients - The array of FEM basis coefficients for the elements for the Jacobian evaluation point
    1317: . coefficients_t - The array of FEM basis time derivative coefficients for the elements
    1318: . probAux      - The PetscDS specifying the auxiliary discretizations
    1319: . coefficientsAux - The array of FEM auxiliary basis coefficients for the elements
    1320: . t            - The time
    1321: - u_tShift     - A multiplier for the dF/du_t term (as opposed to the dF/du term)

    1323:   Output Parameter
    1324: . elemMat              - the element matrices for the Jacobian from each element

    1326:   Note:
    1327: $ Loop over batch of elements (e):
    1328: $   Loop over element matrix entries (f,fc,g,gc --> i,j):
    1329: $     Loop over quadrature points (q):
    1330: $       Make u_q and gradU_q (loops over fields,Nb,Ncomp)
    1331: $         elemMat[i,j] += \psi^{fc}_f(q) g0_{fc,gc}(u, \nabla u) \phi^{gc}_g(q)
    1332: $                      + \psi^{fc}_f(q) \cdot g1_{fc,gc,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
    1333: $                      + \nabla\psi^{fc}_f(q) \cdot g2_{fc,gc,df}(u, \nabla u) \phi^{gc}_g(q)
    1334: $                      + \nabla\psi^{fc}_f(q) \cdot g3_{fc,gc,df,dg}(u, \nabla u) \nabla\phi^{gc}_g(q)
    1335:   Level: developer

    1337: .seealso: PetscFEIntegrateJacobian(), PetscFEIntegrateResidual()
    1338: @*/
    1339: PetscErrorCode PetscFEIntegrateBdJacobian(PetscFE fem, PetscDS prob, PetscInt fieldI, PetscInt fieldJ, PetscInt Ne, PetscFEGeom *fgeom,
    1340:                                           const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS probAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
    1341: {

    1346:   if (fem->ops->integratebdjacobian) {(*fem->ops->integratebdjacobian)(fem, prob, fieldI, fieldJ, Ne, fgeom, coefficients, coefficients_t, probAux, coefficientsAux, t, u_tshift, elemMat);}
    1347:   return(0);
    1348: }

    1350: PetscErrorCode PetscFEGetHeightSubspace(PetscFE fe, PetscInt height, PetscFE *subfe)
    1351: {
    1352:   PetscSpace      P, subP;
    1353:   PetscDualSpace  Q, subQ;
    1354:   PetscQuadrature subq;
    1355:   PetscFEType     fetype;
    1356:   PetscInt        dim, Nc;
    1357:   PetscErrorCode  ierr;

    1362:   if (height == 0) {
    1363:     *subfe = fe;
    1364:     return(0);
    1365:   }
    1366:   PetscFEGetBasisSpace(fe, &P);
    1367:   PetscFEGetDualSpace(fe, &Q);
    1368:   PetscFEGetNumComponents(fe, &Nc);
    1369:   PetscFEGetFaceQuadrature(fe, &subq);
    1370:   PetscDualSpaceGetDimension(Q, &dim);
    1371:   if (height > dim || height < 0) {SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Asked for space at height %D for dimension %D space", height, dim);}
    1372:   if (!fe->subspaces) {PetscCalloc1(dim, &fe->subspaces);}
    1373:   if (height <= dim) {
    1374:     if (!fe->subspaces[height-1]) {
    1375:       PetscFE sub;

    1377:       PetscSpaceGetHeightSubspace(P, height, &subP);
    1378:       PetscDualSpaceGetHeightSubspace(Q, height, &subQ);
    1379:       PetscFECreate(PetscObjectComm((PetscObject) fe), &sub);
    1380:       PetscFEGetType(fe, &fetype);
    1381:       PetscFESetType(sub, fetype);
    1382:       PetscFESetBasisSpace(sub, subP);
    1383:       PetscFESetDualSpace(sub, subQ);
    1384:       PetscFESetNumComponents(sub, Nc);
    1385:       PetscFESetUp(sub);
    1386:       PetscFESetQuadrature(sub, subq);
    1387:       fe->subspaces[height-1] = sub;
    1388:     }
    1389:     *subfe = fe->subspaces[height-1];
    1390:   } else {
    1391:     *subfe = NULL;
    1392:   }
    1393:   return(0);
    1394: }

    1396: /*@
    1397:   PetscFERefine - Create a "refined" PetscFE object that refines the reference cell into smaller copies. This is typically used
    1398:   to precondition a higher order method with a lower order method on a refined mesh having the same number of dofs (but more
    1399:   sparsity). It is also used to create an interpolation between regularly refined meshes.

    1401:   Collective on PetscFE

    1403:   Input Parameter:
    1404: . fe - The initial PetscFE

    1406:   Output Parameter:
    1407: . feRef - The refined PetscFE

    1409:   Level: developer

    1411: .seealso: PetscFEType, PetscFECreate(), PetscFESetType()
    1412: @*/
    1413: PetscErrorCode PetscFERefine(PetscFE fe, PetscFE *feRef)
    1414: {
    1415:   PetscSpace       P, Pref;
    1416:   PetscDualSpace   Q, Qref;
    1417:   DM               K, Kref;
    1418:   PetscQuadrature  q, qref;
    1419:   const PetscReal *v0, *jac;
    1420:   PetscInt         numComp, numSubelements;
    1421:   PetscErrorCode   ierr;

    1424:   PetscFEGetBasisSpace(fe, &P);
    1425:   PetscFEGetDualSpace(fe, &Q);
    1426:   PetscFEGetQuadrature(fe, &q);
    1427:   PetscDualSpaceGetDM(Q, &K);
    1428:   /* Create space */
    1429:   PetscObjectReference((PetscObject) P);
    1430:   Pref = P;
    1431:   /* Create dual space */
    1432:   PetscDualSpaceDuplicate(Q, &Qref);
    1433:   DMRefine(K, PetscObjectComm((PetscObject) fe), &Kref);
    1434:   PetscDualSpaceSetDM(Qref, Kref);
    1435:   DMDestroy(&Kref);
    1436:   PetscDualSpaceSetUp(Qref);
    1437:   /* Create element */
    1438:   PetscFECreate(PetscObjectComm((PetscObject) fe), feRef);
    1439:   PetscFESetType(*feRef, PETSCFECOMPOSITE);
    1440:   PetscFESetBasisSpace(*feRef, Pref);
    1441:   PetscFESetDualSpace(*feRef, Qref);
    1442:   PetscFEGetNumComponents(fe,    &numComp);
    1443:   PetscFESetNumComponents(*feRef, numComp);
    1444:   PetscFESetUp(*feRef);
    1445:   PetscSpaceDestroy(&Pref);
    1446:   PetscDualSpaceDestroy(&Qref);
    1447:   /* Create quadrature */
    1448:   PetscFECompositeGetMapping(*feRef, &numSubelements, &v0, &jac, NULL);
    1449:   PetscQuadratureExpandComposite(q, numSubelements, v0, jac, &qref);
    1450:   PetscFESetQuadrature(*feRef, qref);
    1451:   PetscQuadratureDestroy(&qref);
    1452:   return(0);
    1453: }

    1455: /*@C
    1456:   PetscFECreateDefault - Create a PetscFE for basic FEM computation

    1458:   Collective on DM

    1460:   Input Parameters:
    1461: + comm      - The MPI comm
    1462: . dim       - The spatial dimension
    1463: . Nc        - The number of components
    1464: . isSimplex - Flag for simplex reference cell, otherwise its a tensor product
    1465: . prefix    - The options prefix, or NULL
    1466: - qorder    - The quadrature order

    1468:   Output Parameter:
    1469: . fem - The PetscFE object

    1471:   Level: beginner

    1473: .keywords: PetscFE, finite element
    1474: .seealso: PetscFECreate(), PetscSpaceCreate(), PetscDualSpaceCreate()
    1475: @*/
    1476: PetscErrorCode PetscFECreateDefault(MPI_Comm comm, PetscInt dim, PetscInt Nc, PetscBool isSimplex, const char prefix[], PetscInt qorder, PetscFE *fem)
    1477: {
    1478:   PetscQuadrature q, fq;
    1479:   DM              K;
    1480:   PetscSpace      P;
    1481:   PetscDualSpace  Q;
    1482:   PetscInt        order, quadPointsPerEdge;
    1483:   PetscBool       tensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
    1484:   PetscErrorCode  ierr;

    1487:   /* Create space */
    1488:   PetscSpaceCreate(comm, &P);
    1489:   PetscObjectSetOptionsPrefix((PetscObject) P, prefix);
    1490:   PetscSpacePolynomialSetTensor(P, tensor);
    1491:   PetscSpaceSetNumComponents(P, Nc);
    1492:   PetscSpaceSetNumVariables(P, dim);
    1493:   PetscSpaceSetFromOptions(P);
    1494:   PetscSpaceSetUp(P);
    1495:   PetscSpaceGetDegree(P, &order, NULL);
    1496:   PetscSpacePolynomialGetTensor(P, &tensor);
    1497:   /* Create dual space */
    1498:   PetscDualSpaceCreate(comm, &Q);
    1499:   PetscDualSpaceSetType(Q,PETSCDUALSPACELAGRANGE);
    1500:   PetscObjectSetOptionsPrefix((PetscObject) Q, prefix);
    1501:   PetscDualSpaceCreateReferenceCell(Q, dim, isSimplex, &K);
    1502:   PetscDualSpaceSetDM(Q, K);
    1503:   DMDestroy(&K);
    1504:   PetscDualSpaceSetNumComponents(Q, Nc);
    1505:   PetscDualSpaceSetOrder(Q, order);
    1506:   PetscDualSpaceLagrangeSetTensor(Q, tensor);
    1507:   PetscDualSpaceSetFromOptions(Q);
    1508:   PetscDualSpaceSetUp(Q);
    1509:   /* Create element */
    1510:   PetscFECreate(comm, fem);
    1511:   PetscObjectSetOptionsPrefix((PetscObject) *fem, prefix);
    1512:   PetscFESetFromOptions(*fem);
    1513:   PetscFESetBasisSpace(*fem, P);
    1514:   PetscFESetDualSpace(*fem, Q);
    1515:   PetscFESetNumComponents(*fem, Nc);
    1516:   PetscFESetUp(*fem);
    1517:   PetscSpaceDestroy(&P);
    1518:   PetscDualSpaceDestroy(&Q);
    1519:   /* Create quadrature (with specified order if given) */
    1520:   qorder = qorder >= 0 ? qorder : order;
    1521:   PetscObjectOptionsBegin((PetscObject)*fem);
    1522:   PetscOptionsInt("-petscfe_default_quadrature_order","Quadrature order is one less than quadture points per edge","PetscFECreateDefault",qorder,&qorder,NULL);
    1523:   PetscOptionsEnd();
    1524:   quadPointsPerEdge = PetscMax(qorder + 1,1);
    1525:   if (isSimplex) {
    1526:     PetscDTGaussJacobiQuadrature(dim,   1, quadPointsPerEdge, -1.0, 1.0, &q);
    1527:     PetscDTGaussJacobiQuadrature(dim-1, 1, quadPointsPerEdge, -1.0, 1.0, &fq);
    1528:   }
    1529:   else {
    1530:     PetscDTGaussTensorQuadrature(dim,   1, quadPointsPerEdge, -1.0, 1.0, &q);
    1531:     PetscDTGaussTensorQuadrature(dim-1, 1, quadPointsPerEdge, -1.0, 1.0, &fq);
    1532:   }
    1533:   PetscFESetQuadrature(*fem, q);
    1534:   PetscFESetFaceQuadrature(*fem, fq);
    1535:   PetscQuadratureDestroy(&q);
    1536:   PetscQuadratureDestroy(&fq);
    1537:   return(0);
    1538: }