Date: 2025-03-28T21:10:43+00:00

Actual source code: dtds.c

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

      3: PetscClassId PETSCDS_CLASSID = 0;

      5: PetscFunctionList PetscDSList              = NULL;
      6: PetscBool         PetscDSRegisterAllCalled = PETSC_FALSE;

      8: /* A PetscDS (Discrete System) encodes a set of equations posed in a discrete space, which represents a set of
      9:    nonlinear continuum equations. The equations can have multiple fields, each field having a different
     10:    discretization. In addition, different pieces of the domain can have different field combinations and equations.

     12:    The DS provides the user a description of the approximation space on any given cell. It also gives pointwise
     13:    functions representing the equations.

     15:    Each field is associated with a label, marking the cells on which it is supported. Note that a field can be
     16:    supported on the closure of a cell not in the label due to overlap of the boundary of neighboring cells. The DM
     17:    then creates a DS for each set of cells with identical approximation spaces. When assembling, the user asks for
     18:    the space associated with a given cell. DMPlex uses the labels associated with each DS in the default integration loop.
     19: */

     21: /*@C
     22:   PetscDSRegister - Adds a new `PetscDS` implementation

     24:   Not Collective; No Fortran Support

     26:   Input Parameters:
     27: + sname    - The name of a new user-defined creation routine
     28: - function - The creation routine itself

     30:   Example Usage:
     31: .vb
     32:     PetscDSRegister("my_ds", MyPetscDSCreate);
     33: .ve

     35:   Then, your PetscDS type can be chosen with the procedural interface via
     36: .vb
     37:     PetscDSCreate(MPI_Comm, PetscDS *);
     38:     PetscDSSetType(PetscDS, "my_ds");
     39: .ve
     40:   or at runtime via the option
     41: .vb
     42:     -petscds_type my_ds
     43: .ve

     45:   Level: advanced

     47:   Note:
     48:   `PetscDSRegister()` may be called multiple times to add several user-defined `PetscDSs`

     50: .seealso: `PetscDSType`, `PetscDS`, `PetscDSRegisterAll()`, `PetscDSRegisterDestroy()`
     51: @*/
     52: PetscErrorCode PetscDSRegister(const char sname[], PetscErrorCode (*function)(PetscDS))
     53: {
     54:   PetscFunctionBegin;
     55:   PetscCall(PetscFunctionListAdd(&PetscDSList, sname, function));
     56:   PetscFunctionReturn(PETSC_SUCCESS);
     57: }

     59: /*@
     60:   PetscDSSetType - Builds a particular `PetscDS`

     62:   Collective; No Fortran Support

     64:   Input Parameters:
     65: + prob - The `PetscDS` object
     66: - name - The `PetscDSType`

     68:   Options Database Key:
     69: . -petscds_type <type> - Sets the PetscDS type; use -help for a list of available types

     71:   Level: intermediate

     73: .seealso: `PetscDSType`, `PetscDS`, `PetscDSGetType()`, `PetscDSCreate()`
     74: @*/
     75: PetscErrorCode PetscDSSetType(PetscDS prob, PetscDSType name)
     76: {
     77:   PetscErrorCode (*r)(PetscDS);
     78:   PetscBool match;

     80:   PetscFunctionBegin;
     82:   PetscCall(PetscObjectTypeCompare((PetscObject)prob, name, &match));
     83:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

     85:   PetscCall(PetscDSRegisterAll());
     86:   PetscCall(PetscFunctionListFind(PetscDSList, name, &r));
     87:   PetscCheck(r, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDS type: %s", name);

     89:   PetscTryTypeMethod(prob, destroy);
     90:   prob->ops->destroy = NULL;

     92:   PetscCall((*r)(prob));
     93:   PetscCall(PetscObjectChangeTypeName((PetscObject)prob, name));
     94:   PetscFunctionReturn(PETSC_SUCCESS);
     95: }

     97: /*@
     98:   PetscDSGetType - Gets the `PetscDSType` name (as a string) from the `PetscDS`

    100:   Not Collective; No Fortran Support

    102:   Input Parameter:
    103: . prob - The `PetscDS`

    105:   Output Parameter:
    106: . name - The `PetscDSType` name

    108:   Level: intermediate

    110: .seealso: `PetscDSType`, `PetscDS`, `PetscDSSetType()`, `PetscDSCreate()`
    111: @*/
    112: PetscErrorCode PetscDSGetType(PetscDS prob, PetscDSType *name)
    113: {
    114:   PetscFunctionBegin;
    116:   PetscAssertPointer(name, 2);
    117:   PetscCall(PetscDSRegisterAll());
    118:   *name = ((PetscObject)prob)->type_name;
    119:   PetscFunctionReturn(PETSC_SUCCESS);
    120: }

    122: static PetscErrorCode PetscDSView_Ascii(PetscDS ds, PetscViewer viewer)
    123: {
    124:   PetscViewerFormat  format;
    125:   const PetscScalar *constants;
    126:   PetscInt           Nf, numConstants, f;

    128:   PetscFunctionBegin;
    129:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    130:   PetscCall(PetscViewerGetFormat(viewer, &format));
    131:   PetscCall(PetscViewerASCIIPrintf(viewer, "Discrete System with %" PetscInt_FMT " fields\n", Nf));
    132:   PetscCall(PetscViewerASCIIPushTab(viewer));
    133:   PetscCall(PetscViewerASCIIPrintf(viewer, "  cell total dim %" PetscInt_FMT " total comp %" PetscInt_FMT "\n", ds->totDim, ds->totComp));
    134:   if (ds->isCohesive) PetscCall(PetscViewerASCIIPrintf(viewer, "  cohesive cell\n"));
    135:   for (f = 0; f < Nf; ++f) {
    136:     DSBoundary      b;
    137:     PetscObject     obj;
    138:     PetscClassId    id;
    139:     PetscQuadrature q;
    140:     const char     *name;
    141:     PetscInt        Nc, Nq, Nqc;

    143:     PetscCall(PetscDSGetDiscretization(ds, f, &obj));
    144:     PetscCall(PetscObjectGetClassId(obj, &id));
    145:     PetscCall(PetscObjectGetName(obj, &name));
    146:     PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s", name ? name : "<unknown>"));
    147:     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
    148:     if (id == PETSCFE_CLASSID) {
    149:       PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
    150:       PetscCall(PetscFEGetQuadrature((PetscFE)obj, &q));
    151:       PetscCall(PetscViewerASCIIPrintf(viewer, " FEM"));
    152:     } else if (id == PETSCFV_CLASSID) {
    153:       PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
    154:       PetscCall(PetscFVGetQuadrature((PetscFV)obj, &q));
    155:       PetscCall(PetscViewerASCIIPrintf(viewer, " FVM"));
    156:     } else SETERRQ(PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
    157:     if (Nc > 1) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " components", Nc));
    158:     else PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " component ", Nc));
    159:     if (ds->implicit[f]) PetscCall(PetscViewerASCIIPrintf(viewer, " (implicit)"));
    160:     else PetscCall(PetscViewerASCIIPrintf(viewer, " (explicit)"));
    161:     if (q) {
    162:       PetscCall(PetscQuadratureGetData(q, NULL, &Nqc, &Nq, NULL, NULL));
    163:       PetscCall(PetscViewerASCIIPrintf(viewer, " (Nq %" PetscInt_FMT " Nqc %" PetscInt_FMT ")", Nq, Nqc));
    164:     }
    165:     PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "-jet", ds->jetDegree[f]));
    166:     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
    167:     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
    168:     PetscCall(PetscViewerASCIIPushTab(viewer));
    169:     if (id == PETSCFE_CLASSID) PetscCall(PetscFEView((PetscFE)obj, viewer));
    170:     else if (id == PETSCFV_CLASSID) PetscCall(PetscFVView((PetscFV)obj, viewer));
    171:     PetscCall(PetscViewerASCIIPopTab(viewer));

    173:     for (b = ds->boundary; b; b = b->next) {
    174:       char    *name;
    175:       PetscInt c, i;

    177:       if (b->field != f) continue;
    178:       PetscCall(PetscViewerASCIIPushTab(viewer));
    179:       PetscCall(PetscViewerASCIIPrintf(viewer, "Boundary %s (%s) %s\n", b->name, b->lname, DMBoundaryConditionTypes[b->type]));
    180:       if (!b->Nc) {
    181:         PetscCall(PetscViewerASCIIPrintf(viewer, "  all components\n"));
    182:       } else {
    183:         PetscCall(PetscViewerASCIIPrintf(viewer, "  components: "));
    184:         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
    185:         for (c = 0; c < b->Nc; ++c) {
    186:           if (c > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
    187:           PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT, b->comps[c]));
    188:         }
    189:         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
    190:         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
    191:       }
    192:       PetscCall(PetscViewerASCIIPrintf(viewer, "  values: "));
    193:       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
    194:       for (i = 0; i < b->Nv; ++i) {
    195:         if (i > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
    196:         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT, b->values[i]));
    197:       }
    198:       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
    199:       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
    200: #if defined(__clang__)
    201:       PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wformat-pedantic")
    202: #elif defined(__GNUC__) || defined(__GNUG__)
    203:       PETSC_PRAGMA_DIAGNOSTIC_IGNORED_BEGIN("-Wformat")
    204: #endif
    205:       if (b->func) {
    206:         PetscCall(PetscDLAddr(b->func, &name));
    207:         if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "  func: %s\n", name));
    208:         else PetscCall(PetscViewerASCIIPrintf(viewer, "  func: %p\n", b->func));
    209:         PetscCall(PetscFree(name));
    210:       }
    211:       if (b->func_t) {
    212:         PetscCall(PetscDLAddr(b->func_t, &name));
    213:         if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "  func_t: %s\n", name));
    214:         else PetscCall(PetscViewerASCIIPrintf(viewer, "  func_t: %p\n", b->func_t));
    215:         PetscCall(PetscFree(name));
    216:       }
    217:       PETSC_PRAGMA_DIAGNOSTIC_IGNORED_END()
    218:       PetscCall(PetscWeakFormView(b->wf, viewer));
    219:       PetscCall(PetscViewerASCIIPopTab(viewer));
    220:     }
    221:   }
    222:   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
    223:   if (numConstants) {
    224:     PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " constants\n", numConstants));
    225:     PetscCall(PetscViewerASCIIPushTab(viewer));
    226:     for (f = 0; f < numConstants; ++f) PetscCall(PetscViewerASCIIPrintf(viewer, "%g\n", (double)PetscRealPart(constants[f])));
    227:     PetscCall(PetscViewerASCIIPopTab(viewer));
    228:   }
    229:   PetscCall(PetscWeakFormView(ds->wf, viewer));
    230:   PetscCall(PetscViewerASCIIPopTab(viewer));
    231:   PetscFunctionReturn(PETSC_SUCCESS);
    232: }

    234: /*@
    235:   PetscDSViewFromOptions - View a `PetscDS` based on values in the options database

    237:   Collective

    239:   Input Parameters:
    240: + A    - the `PetscDS` object
    241: . obj  - Optional object that provides the options prefix used in the search
    242: - name - command line option

    244:   Level: intermediate

    246: .seealso: `PetscDSType`, `PetscDS`, `PetscDSView()`, `PetscObjectViewFromOptions()`, `PetscDSCreate()`
    247: @*/
    248: PetscErrorCode PetscDSViewFromOptions(PetscDS A, PetscObject obj, const char name[])
    249: {
    250:   PetscFunctionBegin;
    252:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
    253:   PetscFunctionReturn(PETSC_SUCCESS);
    254: }

    256: /*@
    257:   PetscDSView - Views a `PetscDS`

    259:   Collective

    261:   Input Parameters:
    262: + prob - the `PetscDS` object to view
    263: - v    - the viewer

    265:   Level: developer

    267: .seealso: `PetscDSType`, `PetscDS`, `PetscViewer`, `PetscDSDestroy()`, `PetscDSViewFromOptions()`
    268: @*/
    269: PetscErrorCode PetscDSView(PetscDS prob, PetscViewer v)
    270: {
    271:   PetscBool iascii;

    273:   PetscFunctionBegin;
    275:   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)prob), &v));
    277:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
    278:   if (iascii) PetscCall(PetscDSView_Ascii(prob, v));
    279:   PetscTryTypeMethod(prob, view, v);
    280:   PetscFunctionReturn(PETSC_SUCCESS);
    281: }

    283: /*@
    284:   PetscDSSetFromOptions - sets parameters in a `PetscDS` from the options database

    286:   Collective

    288:   Input Parameter:
    289: . prob - the `PetscDS` object to set options for

    291:   Options Database Keys:
    292: + -petscds_type <type>     - Set the `PetscDS` type
    293: . -petscds_view <view opt> - View the `PetscDS`
    294: . -petscds_jac_pre         - Turn formation of a separate Jacobian preconditioner on or off
    295: . -bc_<name> <ids>         - Specify a list of label ids for a boundary condition
    296: - -bc_<name>_comp <comps>  - Specify a list of field components to constrain for a boundary condition

    298:   Level: intermediate

    300: .seealso: `PetscDS`, `PetscDSView()`
    301: @*/
    302: PetscErrorCode PetscDSSetFromOptions(PetscDS prob)
    303: {
    304:   DSBoundary  b;
    305:   const char *defaultType;
    306:   char        name[256];
    307:   PetscBool   flg;

    309:   PetscFunctionBegin;
    311:   if (!((PetscObject)prob)->type_name) {
    312:     defaultType = PETSCDSBASIC;
    313:   } else {
    314:     defaultType = ((PetscObject)prob)->type_name;
    315:   }
    316:   PetscCall(PetscDSRegisterAll());

    318:   PetscObjectOptionsBegin((PetscObject)prob);
    319:   for (b = prob->boundary; b; b = b->next) {
    320:     char      optname[1024];
    321:     PetscInt  ids[1024], len = 1024;
    322:     PetscBool flg;

    324:     PetscCall(PetscSNPrintf(optname, sizeof(optname), "-bc_%s", b->name));
    325:     PetscCall(PetscMemzero(ids, sizeof(ids)));
    326:     PetscCall(PetscOptionsIntArray(optname, "List of boundary IDs", "", ids, &len, &flg));
    327:     if (flg) {
    328:       b->Nv = len;
    329:       PetscCall(PetscFree(b->values));
    330:       PetscCall(PetscMalloc1(len, &b->values));
    331:       PetscCall(PetscArraycpy(b->values, ids, len));
    332:       PetscCall(PetscWeakFormRewriteKeys(b->wf, b->label, len, b->values));
    333:     }
    334:     len = 1024;
    335:     PetscCall(PetscSNPrintf(optname, sizeof(optname), "-bc_%s_comp", b->name));
    336:     PetscCall(PetscMemzero(ids, sizeof(ids)));
    337:     PetscCall(PetscOptionsIntArray(optname, "List of boundary field components", "", ids, &len, &flg));
    338:     if (flg) {
    339:       b->Nc = len;
    340:       PetscCall(PetscFree(b->comps));
    341:       PetscCall(PetscMalloc1(len, &b->comps));
    342:       PetscCall(PetscArraycpy(b->comps, ids, len));
    343:     }
    344:   }
    345:   PetscCall(PetscOptionsFList("-petscds_type", "Discrete System", "PetscDSSetType", PetscDSList, defaultType, name, 256, &flg));
    346:   if (flg) {
    347:     PetscCall(PetscDSSetType(prob, name));
    348:   } else if (!((PetscObject)prob)->type_name) {
    349:     PetscCall(PetscDSSetType(prob, defaultType));
    350:   }
    351:   PetscCall(PetscOptionsBool("-petscds_jac_pre", "Discrete System", "PetscDSUseJacobianPreconditioner", prob->useJacPre, &prob->useJacPre, &flg));
    352:   PetscCall(PetscOptionsBool("-petscds_force_quad", "Discrete System", "PetscDSSetForceQuad", prob->forceQuad, &prob->forceQuad, &flg));
    353:   PetscCall(PetscOptionsInt("-petscds_print_integrate", "Discrete System", "", prob->printIntegrate, &prob->printIntegrate, NULL));
    354:   PetscTryTypeMethod(prob, setfromoptions);
    355:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
    356:   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)prob, PetscOptionsObject));
    357:   PetscOptionsEnd();
    358:   if (prob->Nf) PetscCall(PetscDSViewFromOptions(prob, NULL, "-petscds_view"));
    359:   PetscFunctionReturn(PETSC_SUCCESS);
    360: }

    362: /*@
    363:   PetscDSSetUp - Construct data structures for the `PetscDS`

    365:   Collective

    367:   Input Parameter:
    368: . prob - the `PetscDS` object to setup

    370:   Level: developer

    372: .seealso: `PetscDS`, `PetscDSView()`, `PetscDSDestroy()`
    373: @*/
    374: PetscErrorCode PetscDSSetUp(PetscDS prob)
    375: {
    376:   const PetscInt Nf          = prob->Nf;
    377:   PetscBool      hasH        = PETSC_FALSE;
    378:   PetscInt       maxOrder[4] = {-2, -2, -2, -2};
    379:   PetscInt       dim, dimEmbed, NbMax = 0, NcMax = 0, NqMax = 0, NsMax = 1, f;

    381:   PetscFunctionBegin;
    383:   if (prob->setup) PetscFunctionReturn(PETSC_SUCCESS);
    384:   /* Calculate sizes */
    385:   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
    386:   PetscCall(PetscDSGetCoordinateDimension(prob, &dimEmbed));
    387:   prob->totDim = prob->totComp = 0;
    388:   PetscCall(PetscMalloc2(Nf, &prob->Nc, Nf, &prob->Nb));
    389:   PetscCall(PetscCalloc2(Nf + 1, &prob->off, Nf + 1, &prob->offDer));
    390:   PetscCall(PetscCalloc6(Nf + 1, &prob->offCohesive[0], Nf + 1, &prob->offCohesive[1], Nf + 1, &prob->offCohesive[2], Nf + 1, &prob->offDerCohesive[0], Nf + 1, &prob->offDerCohesive[1], Nf + 1, &prob->offDerCohesive[2]));
    391:   PetscCall(PetscMalloc2(Nf, &prob->T, Nf, &prob->Tf));
    392:   if (prob->forceQuad) {
    393:     // Note: This assumes we have one kind of cell at each dimension.
    394:     //       We can fix this by having quadrature hold the celltype
    395:     PetscQuadrature maxQuad[4] = {NULL, NULL, NULL, NULL};

    397:     for (f = 0; f < Nf; ++f) {
    398:       PetscObject     obj;
    399:       PetscClassId    id;
    400:       PetscQuadrature q = NULL, fq = NULL;
    401:       PetscInt        dim = -1, order = -1, forder = -1;

    403:       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
    404:       if (!obj) continue;
    405:       PetscCall(PetscObjectGetClassId(obj, &id));
    406:       if (id == PETSCFE_CLASSID) {
    407:         PetscFE fe = (PetscFE)obj;

    409:         PetscCall(PetscFEGetQuadrature(fe, &q));
    410:         PetscCall(PetscFEGetFaceQuadrature(fe, &fq));
    411:       } else if (id == PETSCFV_CLASSID) {
    412:         PetscFV fv = (PetscFV)obj;

    414:         PetscCall(PetscFVGetQuadrature(fv, &q));
    415:       }
    416:       if (q) {
    417:         PetscCall(PetscQuadratureGetData(q, &dim, NULL, NULL, NULL, NULL));
    418:         PetscCall(PetscQuadratureGetOrder(q, &order));
    419:         if (order > maxOrder[dim]) {
    420:           maxOrder[dim] = order;
    421:           maxQuad[dim]  = q;
    422:         }
    423:       }
    424:       if (fq) {
    425:         PetscCall(PetscQuadratureGetData(fq, &dim, NULL, NULL, NULL, NULL));
    426:         PetscCall(PetscQuadratureGetOrder(fq, &forder));
    427:         if (forder > maxOrder[dim]) {
    428:           maxOrder[dim] = forder;
    429:           maxQuad[dim]  = fq;
    430:         }
    431:       }
    432:     }
    433:     for (f = 0; f < Nf; ++f) {
    434:       PetscObject     obj;
    435:       PetscClassId    id;
    436:       PetscQuadrature q;
    437:       PetscInt        dim;

    439:       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
    440:       if (!obj) continue;
    441:       PetscCall(PetscObjectGetClassId(obj, &id));
    442:       if (id == PETSCFE_CLASSID) {
    443:         PetscFE fe = (PetscFE)obj;

    445:         PetscCall(PetscFEGetQuadrature(fe, &q));
    446:         PetscCall(PetscQuadratureGetData(q, &dim, NULL, NULL, NULL, NULL));
    447:         PetscCall(PetscFESetQuadrature(fe, maxQuad[dim]));
    448:         PetscCall(PetscFESetFaceQuadrature(fe, dim ? maxQuad[dim - 1] : NULL));
    449:       } else if (id == PETSCFV_CLASSID) {
    450:         PetscFV fv = (PetscFV)obj;

    452:         PetscCall(PetscFVGetQuadrature(fv, &q));
    453:         PetscCall(PetscQuadratureGetData(q, &dim, NULL, NULL, NULL, NULL));
    454:         PetscCall(PetscFVSetQuadrature(fv, maxQuad[dim]));
    455:       }
    456:     }
    457:   }
    458:   for (f = 0; f < Nf; ++f) {
    459:     PetscObject     obj;
    460:     PetscClassId    id;
    461:     PetscQuadrature q  = NULL;
    462:     PetscInt        Nq = 0, Nb, Nc;

    464:     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
    465:     if (prob->jetDegree[f] > 1) hasH = PETSC_TRUE;
    466:     if (!obj) {
    467:       /* Empty mesh */
    468:       Nb = Nc    = 0;
    469:       prob->T[f] = prob->Tf[f] = NULL;
    470:     } else {
    471:       PetscCall(PetscObjectGetClassId(obj, &id));
    472:       if (id == PETSCFE_CLASSID) {
    473:         PetscFE fe = (PetscFE)obj;

    475:         PetscCall(PetscFEGetQuadrature(fe, &q));
    476:         {
    477:           PetscQuadrature fq;
    478:           PetscInt        dim, order;

    480:           PetscCall(PetscQuadratureGetData(q, &dim, NULL, NULL, NULL, NULL));
    481:           PetscCall(PetscQuadratureGetOrder(q, &order));
    482:           if (maxOrder[dim] < 0) maxOrder[dim] = order;
    483:           PetscCheck(order == maxOrder[dim], PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Field %" PetscInt_FMT " cell quadrature order %" PetscInt_FMT " != %" PetscInt_FMT " DS cell quadrature order", f, order, maxOrder[dim]);
    484:           PetscCall(PetscFEGetFaceQuadrature(fe, &fq));
    485:           if (fq) {
    486:             PetscCall(PetscQuadratureGetData(fq, &dim, NULL, NULL, NULL, NULL));
    487:             PetscCall(PetscQuadratureGetOrder(fq, &order));
    488:             if (maxOrder[dim] < 0) maxOrder[dim] = order;
    489:             PetscCheck(order == maxOrder[dim], PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Field %" PetscInt_FMT " face quadrature order %" PetscInt_FMT " != %" PetscInt_FMT " DS face quadrature order", f, order, maxOrder[dim]);
    490:           }
    491:         }
    492:         PetscCall(PetscFEGetDimension(fe, &Nb));
    493:         PetscCall(PetscFEGetNumComponents(fe, &Nc));
    494:         PetscCall(PetscFEGetCellTabulation(fe, prob->jetDegree[f], &prob->T[f]));
    495:         PetscCall(PetscFEGetFaceTabulation(fe, prob->jetDegree[f], &prob->Tf[f]));
    496:       } else if (id == PETSCFV_CLASSID) {
    497:         PetscFV fv = (PetscFV)obj;

    499:         PetscCall(PetscFVGetQuadrature(fv, &q));
    500:         PetscCall(PetscFVGetNumComponents(fv, &Nc));
    501:         Nb = Nc;
    502:         PetscCall(PetscFVGetCellTabulation(fv, &prob->T[f]));
    503:         /* TODO: should PetscFV also have face tabulation? Otherwise there will be a null pointer in prob->basisFace */
    504:       } else SETERRQ(PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
    505:     }
    506:     prob->Nc[f]                    = Nc;
    507:     prob->Nb[f]                    = Nb;
    508:     prob->off[f + 1]               = Nc + prob->off[f];
    509:     prob->offDer[f + 1]            = Nc * dim + prob->offDer[f];
    510:     prob->offCohesive[0][f + 1]    = (prob->cohesive[f] ? Nc : Nc * 2) + prob->offCohesive[0][f];
    511:     prob->offDerCohesive[0][f + 1] = (prob->cohesive[f] ? Nc : Nc * 2) * dimEmbed + prob->offDerCohesive[0][f];
    512:     prob->offCohesive[1][f]        = (prob->cohesive[f] ? 0 : Nc) + prob->offCohesive[0][f];
    513:     prob->offDerCohesive[1][f]     = (prob->cohesive[f] ? 0 : Nc) * dimEmbed + prob->offDerCohesive[0][f];
    514:     prob->offCohesive[2][f + 1]    = (prob->cohesive[f] ? Nc : Nc * 2) + prob->offCohesive[2][f];
    515:     prob->offDerCohesive[2][f + 1] = (prob->cohesive[f] ? Nc : Nc * 2) * dimEmbed + prob->offDerCohesive[2][f];
    516:     if (q) PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL));
    517:     NqMax = PetscMax(NqMax, Nq);
    518:     NbMax = PetscMax(NbMax, Nb);
    519:     NcMax = PetscMax(NcMax, Nc);
    520:     prob->totDim += Nb;
    521:     prob->totComp += Nc;
    522:     /* There are two faces for all fields on a cohesive cell, except for cohesive fields */
    523:     if (prob->isCohesive && !prob->cohesive[f]) prob->totDim += Nb;
    524:   }
    525:   prob->offCohesive[1][Nf]    = prob->offCohesive[0][Nf];
    526:   prob->offDerCohesive[1][Nf] = prob->offDerCohesive[0][Nf];
    527:   /* Allocate works space */
    528:   NsMax = 2; /* A non-cohesive discretizations can be used on a cohesive cell, so we need this extra workspace for all DS */
    529:   PetscCall(PetscMalloc3(NsMax * prob->totComp, &prob->u, NsMax * prob->totComp, &prob->u_t, NsMax * prob->totComp * dimEmbed + (hasH ? NsMax * prob->totComp * dimEmbed * dimEmbed : 0), &prob->u_x));
    530:   PetscCall(PetscMalloc5(dimEmbed, &prob->x, NbMax * NcMax, &prob->basisReal, NbMax * NcMax * dimEmbed, &prob->basisDerReal, NbMax * NcMax, &prob->testReal, NbMax * NcMax * dimEmbed, &prob->testDerReal));
    531:   PetscCall(PetscMalloc6(NsMax * NqMax * NcMax, &prob->f0, NsMax * NqMax * NcMax * dimEmbed, &prob->f1, NsMax * NsMax * NqMax * NcMax * NcMax, &prob->g0, NsMax * NsMax * NqMax * NcMax * NcMax * dimEmbed, &prob->g1, NsMax * NsMax * NqMax * NcMax * NcMax * dimEmbed,
    532:                          &prob->g2, NsMax * NsMax * NqMax * NcMax * NcMax * dimEmbed * dimEmbed, &prob->g3));
    533:   PetscTryTypeMethod(prob, setup);
    534:   prob->setup = PETSC_TRUE;
    535:   PetscFunctionReturn(PETSC_SUCCESS);
    536: }

    538: static PetscErrorCode PetscDSDestroyStructs_Static(PetscDS prob)
    539: {
    540:   PetscFunctionBegin;
    541:   PetscCall(PetscFree2(prob->Nc, prob->Nb));
    542:   PetscCall(PetscFree2(prob->off, prob->offDer));
    543:   PetscCall(PetscFree6(prob->offCohesive[0], prob->offCohesive[1], prob->offCohesive[2], prob->offDerCohesive[0], prob->offDerCohesive[1], prob->offDerCohesive[2]));
    544:   PetscCall(PetscFree2(prob->T, prob->Tf));
    545:   PetscCall(PetscFree3(prob->u, prob->u_t, prob->u_x));
    546:   PetscCall(PetscFree5(prob->x, prob->basisReal, prob->basisDerReal, prob->testReal, prob->testDerReal));
    547:   PetscCall(PetscFree6(prob->f0, prob->f1, prob->g0, prob->g1, prob->g2, prob->g3));
    548:   PetscFunctionReturn(PETSC_SUCCESS);
    549: }

    551: static PetscErrorCode PetscDSEnlarge_Static(PetscDS prob, PetscInt NfNew)
    552: {
    553:   PetscObject         *tmpd;
    554:   PetscBool           *tmpi;
    555:   PetscInt            *tmpk;
    556:   PetscBool           *tmpc;
    557:   PetscPointFunc      *tmpup;
    558:   PetscSimplePointFn **tmpexactSol, **tmpexactSol_t;
    559:   void               **tmpexactCtx, **tmpexactCtx_t;
    560:   void               **tmpctx;
    561:   PetscInt             Nf = prob->Nf, f;

    563:   PetscFunctionBegin;
    564:   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
    565:   prob->setup = PETSC_FALSE;
    566:   PetscCall(PetscDSDestroyStructs_Static(prob));
    567:   PetscCall(PetscMalloc4(NfNew, &tmpd, NfNew, &tmpi, NfNew, &tmpc, NfNew, &tmpk));
    568:   for (f = 0; f < Nf; ++f) {
    569:     tmpd[f] = prob->disc[f];
    570:     tmpi[f] = prob->implicit[f];
    571:     tmpc[f] = prob->cohesive[f];
    572:     tmpk[f] = prob->jetDegree[f];
    573:   }
    574:   for (f = Nf; f < NfNew; ++f) {
    575:     tmpd[f] = NULL;
    576:     tmpi[f] = PETSC_TRUE, tmpc[f] = PETSC_FALSE;
    577:     tmpk[f] = 1;
    578:   }
    579:   PetscCall(PetscFree4(prob->disc, prob->implicit, prob->cohesive, prob->jetDegree));
    580:   PetscCall(PetscWeakFormSetNumFields(prob->wf, NfNew));
    581:   prob->Nf        = NfNew;
    582:   prob->disc      = tmpd;
    583:   prob->implicit  = tmpi;
    584:   prob->cohesive  = tmpc;
    585:   prob->jetDegree = tmpk;
    586:   PetscCall(PetscCalloc2(NfNew, &tmpup, NfNew, &tmpctx));
    587:   for (f = 0; f < Nf; ++f) tmpup[f] = prob->update[f];
    588:   for (f = 0; f < Nf; ++f) tmpctx[f] = prob->ctx[f];
    589:   for (f = Nf; f < NfNew; ++f) tmpup[f] = NULL;
    590:   for (f = Nf; f < NfNew; ++f) tmpctx[f] = NULL;
    591:   PetscCall(PetscFree2(prob->update, prob->ctx));
    592:   prob->update = tmpup;
    593:   prob->ctx    = tmpctx;
    594:   PetscCall(PetscCalloc4(NfNew, &tmpexactSol, NfNew, &tmpexactCtx, NfNew, &tmpexactSol_t, NfNew, &tmpexactCtx_t));
    595:   for (f = 0; f < Nf; ++f) tmpexactSol[f] = prob->exactSol[f];
    596:   for (f = 0; f < Nf; ++f) tmpexactCtx[f] = prob->exactCtx[f];
    597:   for (f = 0; f < Nf; ++f) tmpexactSol_t[f] = prob->exactSol_t[f];
    598:   for (f = 0; f < Nf; ++f) tmpexactCtx_t[f] = prob->exactCtx_t[f];
    599:   for (f = Nf; f < NfNew; ++f) tmpexactSol[f] = NULL;
    600:   for (f = Nf; f < NfNew; ++f) tmpexactCtx[f] = NULL;
    601:   for (f = Nf; f < NfNew; ++f) tmpexactSol_t[f] = NULL;
    602:   for (f = Nf; f < NfNew; ++f) tmpexactCtx_t[f] = NULL;
    603:   PetscCall(PetscFree4(prob->exactSol, prob->exactCtx, prob->exactSol_t, prob->exactCtx_t));
    604:   prob->exactSol   = tmpexactSol;
    605:   prob->exactCtx   = tmpexactCtx;
    606:   prob->exactSol_t = tmpexactSol_t;
    607:   prob->exactCtx_t = tmpexactCtx_t;
    608:   PetscFunctionReturn(PETSC_SUCCESS);
    609: }

    611: /*@
    612:   PetscDSDestroy - Destroys a `PetscDS` object

    614:   Collective

    616:   Input Parameter:
    617: . ds - the `PetscDS` object to destroy

    619:   Level: developer

    621: .seealso: `PetscDSView()`
    622: @*/
    623: PetscErrorCode PetscDSDestroy(PetscDS *ds)
    624: {
    625:   PetscInt f;

    627:   PetscFunctionBegin;
    628:   if (!*ds) PetscFunctionReturn(PETSC_SUCCESS);

    631:   if (--((PetscObject)*ds)->refct > 0) {
    632:     *ds = NULL;
    633:     PetscFunctionReturn(PETSC_SUCCESS);
    634:   }
    635:   ((PetscObject)*ds)->refct = 0;
    636:   if ((*ds)->subprobs) {
    637:     PetscInt dim, d;

    639:     PetscCall(PetscDSGetSpatialDimension(*ds, &dim));
    640:     for (d = 0; d < dim; ++d) PetscCall(PetscDSDestroy(&(*ds)->subprobs[d]));
    641:   }
    642:   PetscCall(PetscFree((*ds)->subprobs));
    643:   PetscCall(PetscDSDestroyStructs_Static(*ds));
    644:   for (f = 0; f < (*ds)->Nf; ++f) PetscCall(PetscObjectDereference((*ds)->disc[f]));
    645:   PetscCall(PetscFree4((*ds)->disc, (*ds)->implicit, (*ds)->cohesive, (*ds)->jetDegree));
    646:   PetscCall(PetscWeakFormDestroy(&(*ds)->wf));
    647:   PetscCall(PetscFree2((*ds)->update, (*ds)->ctx));
    648:   PetscCall(PetscFree4((*ds)->exactSol, (*ds)->exactCtx, (*ds)->exactSol_t, (*ds)->exactCtx_t));
    649:   PetscTryTypeMethod(*ds, destroy);
    650:   PetscCall(PetscDSDestroyBoundary(*ds));
    651:   PetscCall(PetscFree((*ds)->constants));
    652:   for (PetscInt c = 0; c < DM_NUM_POLYTOPES; ++c) {
    653:     const PetscInt Na = DMPolytopeTypeGetNumArrangements((DMPolytopeType)c);
    654:     if ((*ds)->quadPerm[c])
    655:       for (PetscInt o = 0; o < Na; ++o) PetscCall(ISDestroy(&(*ds)->quadPerm[c][o]));
    656:     PetscCall(PetscFree((*ds)->quadPerm[c]));
    657:     (*ds)->quadPerm[c] = NULL;
    658:   }
    659:   PetscCall(PetscHeaderDestroy(ds));
    660:   PetscFunctionReturn(PETSC_SUCCESS);
    661: }

    663: /*@
    664:   PetscDSCreate - Creates an empty `PetscDS` object. The type can then be set with `PetscDSSetType()`.

    666:   Collective

    668:   Input Parameter:
    669: . comm - The communicator for the `PetscDS` object

    671:   Output Parameter:
    672: . ds - The `PetscDS` object

    674:   Level: beginner

    676: .seealso: `PetscDS`, `PetscDSSetType()`, `PETSCDSBASIC`, `PetscDSType`
    677: @*/
    678: PetscErrorCode PetscDSCreate(MPI_Comm comm, PetscDS *ds)
    679: {
    680:   PetscDS p;

    682:   PetscFunctionBegin;
    683:   PetscAssertPointer(ds, 2);
    684:   PetscCall(PetscDSInitializePackage());

    686:   PetscCall(PetscHeaderCreate(p, PETSCDS_CLASSID, "PetscDS", "Discrete System", "PetscDS", comm, PetscDSDestroy, PetscDSView));
    687:   p->Nf               = 0;
    688:   p->setup            = PETSC_FALSE;
    689:   p->numConstants     = 0;
    690:   p->numFuncConstants = 3; // Row and col fields, cell size
    691:   p->dimEmbed         = -1;
    692:   p->useJacPre        = PETSC_TRUE;
    693:   p->forceQuad        = PETSC_TRUE;
    694:   PetscCall(PetscMalloc1(p->numConstants + p->numFuncConstants, &p->constants));
    695:   PetscCall(PetscWeakFormCreate(comm, &p->wf));
    696:   PetscCall(PetscArrayzero(p->quadPerm, DM_NUM_POLYTOPES));
    697:   *ds = p;
    698:   PetscFunctionReturn(PETSC_SUCCESS);
    699: }

    701: /*@
    702:   PetscDSGetNumFields - Returns the number of fields in the `PetscDS`

    704:   Not Collective

    706:   Input Parameter:
    707: . prob - The `PetscDS` object

    709:   Output Parameter:
    710: . Nf - The number of fields

    712:   Level: beginner

    714: .seealso: `PetscDS`, `PetscDSGetSpatialDimension()`, `PetscDSCreate()`
    715: @*/
    716: PetscErrorCode PetscDSGetNumFields(PetscDS prob, PetscInt *Nf)
    717: {
    718:   PetscFunctionBegin;
    720:   PetscAssertPointer(Nf, 2);
    721:   *Nf = prob->Nf;
    722:   PetscFunctionReturn(PETSC_SUCCESS);
    723: }

    725: /*@
    726:   PetscDSGetSpatialDimension - Returns the spatial dimension of the `PetscDS`, meaning the topological dimension of the discretizations

    728:   Not Collective

    730:   Input Parameter:
    731: . prob - The `PetscDS` object

    733:   Output Parameter:
    734: . dim - The spatial dimension

    736:   Level: beginner

    738: .seealso: `PetscDS`, `PetscDSGetCoordinateDimension()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    739: @*/
    740: PetscErrorCode PetscDSGetSpatialDimension(PetscDS prob, PetscInt *dim)
    741: {
    742:   PetscFunctionBegin;
    744:   PetscAssertPointer(dim, 2);
    745:   *dim = 0;
    746:   if (prob->Nf) {
    747:     PetscObject  obj;
    748:     PetscClassId id;

    750:     PetscCall(PetscDSGetDiscretization(prob, 0, &obj));
    751:     if (obj) {
    752:       PetscCall(PetscObjectGetClassId(obj, &id));
    753:       if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetSpatialDimension((PetscFE)obj, dim));
    754:       else if (id == PETSCFV_CLASSID) PetscCall(PetscFVGetSpatialDimension((PetscFV)obj, dim));
    755:       else SETERRQ(PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", 0);
    756:     }
    757:   }
    758:   PetscFunctionReturn(PETSC_SUCCESS);
    759: }

    761: /*@
    762:   PetscDSGetCoordinateDimension - Returns the coordinate dimension of the `PetscDS`, meaning the dimension of the space into which the discretiaztions are embedded

    764:   Not Collective

    766:   Input Parameter:
    767: . prob - The `PetscDS` object

    769:   Output Parameter:
    770: . dimEmbed - The coordinate dimension

    772:   Level: beginner

    774: .seealso: `PetscDS`, `PetscDSSetCoordinateDimension()`, `PetscDSGetSpatialDimension()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    775: @*/
    776: PetscErrorCode PetscDSGetCoordinateDimension(PetscDS prob, PetscInt *dimEmbed)
    777: {
    778:   PetscFunctionBegin;
    780:   PetscAssertPointer(dimEmbed, 2);
    781:   PetscCheck(prob->dimEmbed >= 0, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONGSTATE, "No coordinate dimension set for this DS");
    782:   *dimEmbed = prob->dimEmbed;
    783:   PetscFunctionReturn(PETSC_SUCCESS);
    784: }

    786: /*@
    787:   PetscDSSetCoordinateDimension - Set the coordinate dimension of the `PetscDS`, meaning the dimension of the space into which the discretiaztions are embedded

    789:   Logically Collective

    791:   Input Parameters:
    792: + prob     - The `PetscDS` object
    793: - dimEmbed - The coordinate dimension

    795:   Level: beginner

    797: .seealso: `PetscDS`, `PetscDSGetCoordinateDimension()`, `PetscDSGetSpatialDimension()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    798: @*/
    799: PetscErrorCode PetscDSSetCoordinateDimension(PetscDS prob, PetscInt dimEmbed)
    800: {
    801:   PetscFunctionBegin;
    803:   PetscCheck(dimEmbed >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate dimension must be non-negative, not %" PetscInt_FMT, dimEmbed);
    804:   prob->dimEmbed = dimEmbed;
    805:   PetscFunctionReturn(PETSC_SUCCESS);
    806: }

    808: /*@
    809:   PetscDSGetForceQuad - Returns the flag to force matching quadratures among the field discretizations

    811:   Not collective

    813:   Input Parameter:
    814: . ds - The `PetscDS` object

    816:   Output Parameter:
    817: . forceQuad - The flag

    819:   Level: intermediate

    821: .seealso: `PetscDS`, `PetscDSSetForceQuad()`, `PetscDSGetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    822: @*/
    823: PetscErrorCode PetscDSGetForceQuad(PetscDS ds, PetscBool *forceQuad)
    824: {
    825:   PetscFunctionBegin;
    827:   PetscAssertPointer(forceQuad, 2);
    828:   *forceQuad = ds->forceQuad;
    829:   PetscFunctionReturn(PETSC_SUCCESS);
    830: }

    832: /*@
    833:   PetscDSSetForceQuad - Set the flag to force matching quadratures among the field discretizations

    835:   Logically collective on ds

    837:   Input Parameters:
    838: + ds        - The `PetscDS` object
    839: - forceQuad - The flag

    841:   Level: intermediate

    843: .seealso: `PetscDS`, `PetscDSGetForceQuad()`, `PetscDSGetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    844: @*/
    845: PetscErrorCode PetscDSSetForceQuad(PetscDS ds, PetscBool forceQuad)
    846: {
    847:   PetscFunctionBegin;
    849:   ds->forceQuad = forceQuad;
    850:   PetscFunctionReturn(PETSC_SUCCESS);
    851: }

    853: /*@
    854:   PetscDSIsCohesive - Returns the flag indicating that this `PetscDS` is for a cohesive cell

    856:   Not Collective

    858:   Input Parameter:
    859: . ds - The `PetscDS` object

    861:   Output Parameter:
    862: . isCohesive - The flag

    864:   Level: developer

    866: .seealso: `PetscDS`, `PetscDSGetNumCohesive()`, `PetscDSGetCohesive()`, `PetscDSSetCohesive()`, `PetscDSCreate()`
    867: @*/
    868: PetscErrorCode PetscDSIsCohesive(PetscDS ds, PetscBool *isCohesive)
    869: {
    870:   PetscFunctionBegin;
    872:   PetscAssertPointer(isCohesive, 2);
    873:   *isCohesive = ds->isCohesive;
    874:   PetscFunctionReturn(PETSC_SUCCESS);
    875: }

    877: /*@
    878:   PetscDSGetNumCohesive - Returns the number of cohesive fields, meaning those defined on the interior of a cohesive cell

    880:   Not Collective

    882:   Input Parameter:
    883: . ds - The `PetscDS` object

    885:   Output Parameter:
    886: . numCohesive - The number of cohesive fields

    888:   Level: developer

    890: .seealso: `PetscDS`, `PetscDSSetCohesive()`, `PetscDSCreate()`
    891: @*/
    892: PetscErrorCode PetscDSGetNumCohesive(PetscDS ds, PetscInt *numCohesive)
    893: {
    894:   PetscInt f;

    896:   PetscFunctionBegin;
    898:   PetscAssertPointer(numCohesive, 2);
    899:   *numCohesive = 0;
    900:   for (f = 0; f < ds->Nf; ++f) *numCohesive += ds->cohesive[f] ? 1 : 0;
    901:   PetscFunctionReturn(PETSC_SUCCESS);
    902: }

    904: /*@
    905:   PetscDSGetCohesive - Returns the flag indicating that a field is cohesive, meaning it is defined on the interior of a cohesive cell

    907:   Not Collective

    909:   Input Parameters:
    910: + ds - The `PetscDS` object
    911: - f  - The field index

    913:   Output Parameter:
    914: . isCohesive - The flag

    916:   Level: developer

    918: .seealso: `PetscDS`, `PetscDSSetCohesive()`, `PetscDSIsCohesive()`, `PetscDSCreate()`
    919: @*/
    920: PetscErrorCode PetscDSGetCohesive(PetscDS ds, PetscInt f, PetscBool *isCohesive)
    921: {
    922:   PetscFunctionBegin;
    924:   PetscAssertPointer(isCohesive, 3);
    925:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    926:   *isCohesive = ds->cohesive[f];
    927:   PetscFunctionReturn(PETSC_SUCCESS);
    928: }

    930: /*@
    931:   PetscDSSetCohesive - Set the flag indicating that a field is cohesive, meaning it is defined on the interior of a cohesive cell

    933:   Not Collective

    935:   Input Parameters:
    936: + ds         - The `PetscDS` object
    937: . f          - The field index
    938: - isCohesive - The flag for a cohesive field

    940:   Level: developer

    942: .seealso: `PetscDS`, `PetscDSGetCohesive()`, `PetscDSIsCohesive()`, `PetscDSCreate()`
    943: @*/
    944: PetscErrorCode PetscDSSetCohesive(PetscDS ds, PetscInt f, PetscBool isCohesive)
    945: {
    946:   PetscInt i;

    948:   PetscFunctionBegin;
    950:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    951:   ds->cohesive[f] = isCohesive;
    952:   ds->isCohesive  = PETSC_FALSE;
    953:   for (i = 0; i < ds->Nf; ++i) ds->isCohesive = ds->isCohesive || ds->cohesive[f] ? PETSC_TRUE : PETSC_FALSE;
    954:   PetscFunctionReturn(PETSC_SUCCESS);
    955: }

    957: /*@
    958:   PetscDSGetTotalDimension - Returns the total size of the approximation space for this system

    960:   Not Collective

    962:   Input Parameter:
    963: . prob - The `PetscDS` object

    965:   Output Parameter:
    966: . dim - The total problem dimension

    968:   Level: beginner

    970: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    971: @*/
    972: PetscErrorCode PetscDSGetTotalDimension(PetscDS prob, PetscInt *dim)
    973: {
    974:   PetscFunctionBegin;
    976:   PetscCall(PetscDSSetUp(prob));
    977:   PetscAssertPointer(dim, 2);
    978:   *dim = prob->totDim;
    979:   PetscFunctionReturn(PETSC_SUCCESS);
    980: }

    982: /*@
    983:   PetscDSGetTotalComponents - Returns the total number of components in this system

    985:   Not Collective

    987:   Input Parameter:
    988: . prob - The `PetscDS` object

    990:   Output Parameter:
    991: . Nc - The total number of components

    993:   Level: beginner

    995: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    996: @*/
    997: PetscErrorCode PetscDSGetTotalComponents(PetscDS prob, PetscInt *Nc)
    998: {
    999:   PetscFunctionBegin;
    1001:   PetscCall(PetscDSSetUp(prob));
    1002:   PetscAssertPointer(Nc, 2);
    1003:   *Nc = prob->totComp;
    1004:   PetscFunctionReturn(PETSC_SUCCESS);
    1005: }

    1007: /*@
    1008:   PetscDSGetDiscretization - Returns the discretization object for the given field

    1010:   Not Collective

    1012:   Input Parameters:
    1013: + prob - The `PetscDS` object
    1014: - f    - The field number

    1016:   Output Parameter:
    1017: . disc - The discretization object

    1019:   Level: beginner

    1021: .seealso: `PetscDS`, `PetscFE`, `PetscFV`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1022: @*/
    1023: PetscErrorCode PetscDSGetDiscretization(PetscDS prob, PetscInt f, PetscObject *disc)
    1024: {
    1025:   PetscFunctionBeginHot;
    1027:   PetscAssertPointer(disc, 3);
    1028:   PetscCheck(!(f < 0) && !(f >= prob->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, prob->Nf);
    1029:   *disc = prob->disc[f];
    1030:   PetscFunctionReturn(PETSC_SUCCESS);
    1031: }

    1033: /*@
    1034:   PetscDSSetDiscretization - Sets the discretization object for the given field

    1036:   Not Collective

    1038:   Input Parameters:
    1039: + prob - The `PetscDS` object
    1040: . f    - The field number
    1041: - disc - The discretization object

    1043:   Level: beginner

    1045: .seealso: `PetscDS`, `PetscFE`, `PetscFV`, `PetscDSGetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1046: @*/
    1047: PetscErrorCode PetscDSSetDiscretization(PetscDS prob, PetscInt f, PetscObject disc)
    1048: {
    1049:   PetscFunctionBegin;
    1051:   if (disc) PetscAssertPointer(disc, 3);
    1052:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1053:   PetscCall(PetscDSEnlarge_Static(prob, f + 1));
    1054:   PetscCall(PetscObjectDereference(prob->disc[f]));
    1055:   prob->disc[f] = disc;
    1056:   PetscCall(PetscObjectReference(disc));
    1057:   if (disc) {
    1058:     PetscClassId id;

    1060:     PetscCall(PetscObjectGetClassId(disc, &id));
    1061:     if (id == PETSCFE_CLASSID) {
    1062:       PetscCall(PetscDSSetImplicit(prob, f, PETSC_TRUE));
    1063:     } else if (id == PETSCFV_CLASSID) {
    1064:       PetscCall(PetscDSSetImplicit(prob, f, PETSC_FALSE));
    1065:     }
    1066:     PetscCall(PetscDSSetJetDegree(prob, f, 1));
    1067:   }
    1068:   PetscFunctionReturn(PETSC_SUCCESS);
    1069: }

    1071: /*@
    1072:   PetscDSGetWeakForm - Returns the weak form object

    1074:   Not Collective

    1076:   Input Parameter:
    1077: . ds - The `PetscDS` object

    1079:   Output Parameter:
    1080: . wf - The weak form object

    1082:   Level: beginner

    1084: .seealso: `PetscWeakForm`, `PetscDSSetWeakForm()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1085: @*/
    1086: PetscErrorCode PetscDSGetWeakForm(PetscDS ds, PetscWeakForm *wf)
    1087: {
    1088:   PetscFunctionBegin;
    1090:   PetscAssertPointer(wf, 2);
    1091:   *wf = ds->wf;
    1092:   PetscFunctionReturn(PETSC_SUCCESS);
    1093: }

    1095: /*@
    1096:   PetscDSSetWeakForm - Sets the weak form object

    1098:   Not Collective

    1100:   Input Parameters:
    1101: + ds - The `PetscDS` object
    1102: - wf - The weak form object

    1104:   Level: beginner

    1106: .seealso: `PetscWeakForm`, `PetscDSGetWeakForm()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1107: @*/
    1108: PetscErrorCode PetscDSSetWeakForm(PetscDS ds, PetscWeakForm wf)
    1109: {
    1110:   PetscFunctionBegin;
    1113:   PetscCall(PetscObjectDereference((PetscObject)ds->wf));
    1114:   ds->wf = wf;
    1115:   PetscCall(PetscObjectReference((PetscObject)wf));
    1116:   PetscCall(PetscWeakFormSetNumFields(wf, ds->Nf));
    1117:   PetscFunctionReturn(PETSC_SUCCESS);
    1118: }

    1120: /*@
    1121:   PetscDSAddDiscretization - Adds a discretization object

    1123:   Not Collective

    1125:   Input Parameters:
    1126: + prob - The `PetscDS` object
    1127: - disc - The boundary discretization object

    1129:   Level: beginner

    1131: .seealso: `PetscWeakForm`, `PetscDSGetDiscretization()`, `PetscDSSetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1132: @*/
    1133: PetscErrorCode PetscDSAddDiscretization(PetscDS prob, PetscObject disc)
    1134: {
    1135:   PetscFunctionBegin;
    1136:   PetscCall(PetscDSSetDiscretization(prob, prob->Nf, disc));
    1137:   PetscFunctionReturn(PETSC_SUCCESS);
    1138: }

    1140: /*@
    1141:   PetscDSGetQuadrature - Returns the quadrature, which must agree for all fields in the `PetscDS`

    1143:   Not Collective

    1145:   Input Parameter:
    1146: . prob - The `PetscDS` object

    1148:   Output Parameter:
    1149: . q - The quadrature object

    1151:   Level: intermediate

    1153: .seealso: `PetscDS`, `PetscQuadrature`, `PetscDSSetImplicit()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1154: @*/
    1155: PetscErrorCode PetscDSGetQuadrature(PetscDS prob, PetscQuadrature *q)
    1156: {
    1157:   PetscObject  obj;
    1158:   PetscClassId id;

    1160:   PetscFunctionBegin;
    1161:   *q = NULL;
    1162:   if (!prob->Nf) PetscFunctionReturn(PETSC_SUCCESS);
    1163:   PetscCall(PetscDSGetDiscretization(prob, 0, &obj));
    1164:   PetscCall(PetscObjectGetClassId(obj, &id));
    1165:   if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, q));
    1166:   else if (id == PETSCFV_CLASSID) PetscCall(PetscFVGetQuadrature((PetscFV)obj, q));
    1167:   else SETERRQ(PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", 0);
    1168:   PetscFunctionReturn(PETSC_SUCCESS);
    1169: }

    1171: /*@
    1172:   PetscDSGetImplicit - Returns the flag for implicit solve for this field. This is just a guide for `TSARKIMEX`

    1174:   Not Collective

    1176:   Input Parameters:
    1177: + prob - The `PetscDS` object
    1178: - f    - The field number

    1180:   Output Parameter:
    1181: . implicit - The flag indicating what kind of solve to use for this field

    1183:   Level: developer

    1185: .seealso: `TSARKIMEX`, `PetscDS`, `PetscDSSetImplicit()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1186: @*/
    1187: PetscErrorCode PetscDSGetImplicit(PetscDS prob, PetscInt f, PetscBool *implicit)
    1188: {
    1189:   PetscFunctionBegin;
    1191:   PetscAssertPointer(implicit, 3);
    1192:   PetscCheck(!(f < 0) && !(f >= prob->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, prob->Nf);
    1193:   *implicit = prob->implicit[f];
    1194:   PetscFunctionReturn(PETSC_SUCCESS);
    1195: }

    1197: /*@
    1198:   PetscDSSetImplicit - Set the flag for implicit solve for this field. This is just a guide for `TSARKIMEX`

    1200:   Not Collective

    1202:   Input Parameters:
    1203: + prob     - The `PetscDS` object
    1204: . f        - The field number
    1205: - implicit - The flag indicating what kind of solve to use for this field

    1207:   Level: developer

    1209: .seealso: `TSARKIMEX`, `PetscDSGetImplicit()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1210: @*/
    1211: PetscErrorCode PetscDSSetImplicit(PetscDS prob, PetscInt f, PetscBool implicit)
    1212: {
    1213:   PetscFunctionBegin;
    1215:   PetscCheck(!(f < 0) && !(f >= prob->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, prob->Nf);
    1216:   prob->implicit[f] = implicit;
    1217:   PetscFunctionReturn(PETSC_SUCCESS);
    1218: }

    1220: /*@
    1221:   PetscDSGetJetDegree - Returns the highest derivative for this field equation, or the k-jet that the discretization needs to tabulate.

    1223:   Not Collective

    1225:   Input Parameters:
    1226: + ds - The `PetscDS` object
    1227: - f  - The field number

    1229:   Output Parameter:
    1230: . k - The highest derivative we need to tabulate

    1232:   Level: developer

    1234: .seealso: `PetscDS`, `PetscDSSetJetDegree()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1235: @*/
    1236: PetscErrorCode PetscDSGetJetDegree(PetscDS ds, PetscInt f, PetscInt *k)
    1237: {
    1238:   PetscFunctionBegin;
    1240:   PetscAssertPointer(k, 3);
    1241:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    1242:   *k = ds->jetDegree[f];
    1243:   PetscFunctionReturn(PETSC_SUCCESS);
    1244: }

    1246: /*@
    1247:   PetscDSSetJetDegree - Set the highest derivative for this field equation, or the k-jet that the discretization needs to tabulate.

    1249:   Not Collective

    1251:   Input Parameters:
    1252: + ds - The `PetscDS` object
    1253: . f  - The field number
    1254: - k  - The highest derivative we need to tabulate

    1256:   Level: developer

    1258: .seealso: `PetscDS`, `PetscDSGetJetDegree()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1259: @*/
    1260: PetscErrorCode PetscDSSetJetDegree(PetscDS ds, PetscInt f, PetscInt k)
    1261: {
    1262:   PetscFunctionBegin;
    1264:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    1265:   ds->jetDegree[f] = k;
    1266:   PetscFunctionReturn(PETSC_SUCCESS);
    1267: }

    1269: /*@C
    1270:   PetscDSGetObjective - Get the pointwise objective function for a given test field

    1272:   Not Collective

    1274:   Input Parameters:
    1275: + ds - The `PetscDS`
    1276: - f  - The test field number

    1278:   Output Parameter:
    1279: . obj - integrand for the test function term

    1281:   Calling sequence of `obj`:
    1282: + dim          - the spatial dimension
    1283: . Nf           - the number of fields
    1284: . NfAux        - the number of auxiliary fields
    1285: . uOff         - the offset into u[] and u_t[] for each field
    1286: . uOff_x       - the offset into u_x[] for each field
    1287: . u            - each field evaluated at the current point
    1288: . u_t          - the time derivative of each field evaluated at the current point
    1289: . u_x          - the gradient of each field evaluated at the current point
    1290: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1291: . aOff_x       - the offset into a_x[] for each auxiliary field
    1292: . a            - each auxiliary field evaluated at the current point
    1293: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1294: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1295: . t            - current time
    1296: . x            - coordinates of the current point
    1297: . numConstants - number of constant parameters
    1298: . constants    - constant parameters
    1299: - obj          - output values at the current point

    1301:   Level: intermediate

    1303:   Note:
    1304:   We are using a first order FEM model for the weak form\: $  \int_\Omega \phi\,\mathrm{obj}(u, u_t, \nabla u, x, t)$

    1306: .seealso: `PetscDS`, `PetscDSSetObjective()`, `PetscDSGetResidual()`
    1307: @*/
    1308: PetscErrorCode PetscDSGetObjective(PetscDS ds, PetscInt f, void (**obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
    1309: {
    1310:   PetscPointFunc *tmp;
    1311:   PetscInt        n;

    1313:   PetscFunctionBegin;
    1315:   PetscAssertPointer(obj, 3);
    1316:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    1317:   PetscCall(PetscWeakFormGetObjective(ds->wf, NULL, 0, f, 0, &n, &tmp));
    1318:   *obj = tmp ? tmp[0] : NULL;
    1319:   PetscFunctionReturn(PETSC_SUCCESS);
    1320: }

    1322: /*@C
    1323:   PetscDSSetObjective - Set the pointwise objective function for a given test field

    1325:   Not Collective

    1327:   Input Parameters:
    1328: + ds  - The `PetscDS`
    1329: . f   - The test field number
    1330: - obj - integrand for the test function term

    1332:   Calling sequence of `obj`:
    1333: + dim          - the spatial dimension
    1334: . Nf           - the number of fields
    1335: . NfAux        - the number of auxiliary fields
    1336: . uOff         - the offset into u[] and u_t[] for each field
    1337: . uOff_x       - the offset into u_x[] for each field
    1338: . u            - each field evaluated at the current point
    1339: . u_t          - the time derivative of each field evaluated at the current point
    1340: . u_x          - the gradient of each field evaluated at the current point
    1341: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1342: . aOff_x       - the offset into a_x[] for each auxiliary field
    1343: . a            - each auxiliary field evaluated at the current point
    1344: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1345: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1346: . t            - current time
    1347: . x            - coordinates of the current point
    1348: . numConstants - number of constant parameters
    1349: . constants    - constant parameters
    1350: - obj          - output values at the current point

    1352:   Level: intermediate

    1354:   Note:
    1355:   We are using a first order FEM model for the weak form\: $  \int_\Omega \phi\,\mathrm{obj}(u, u_t, \nabla u, x, t)$

    1357: .seealso: `PetscDS`, `PetscDSGetObjective()`, `PetscDSSetResidual()`
    1358: @*/
    1359: PetscErrorCode PetscDSSetObjective(PetscDS ds, PetscInt f, void (*obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
    1360: {
    1361:   PetscFunctionBegin;
    1364:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1365:   PetscCall(PetscWeakFormSetIndexObjective(ds->wf, NULL, 0, f, 0, 0, obj));
    1366:   PetscFunctionReturn(PETSC_SUCCESS);
    1367: }

    1369: /*@C
    1370:   PetscDSGetResidual - Get the pointwise residual function for a given test field

    1372:   Not Collective

    1374:   Input Parameters:
    1375: + ds - The `PetscDS`
    1376: - f  - The test field number

    1378:   Output Parameters:
    1379: + f0 - integrand for the test function term
    1380: - f1 - integrand for the test function gradient term

    1382:   Calling sequence of `f0`:
    1383: + dim          - the spatial dimension
    1384: . Nf           - the number of fields
    1385: . NfAux        - the number of auxiliary fields
    1386: . uOff         - the offset into u[] and u_t[] for each field
    1387: . uOff_x       - the offset into u_x[] for each field
    1388: . u            - each field evaluated at the current point
    1389: . u_t          - the time derivative of each field evaluated at the current point
    1390: . u_x          - the gradient of each field evaluated at the current point
    1391: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1392: . aOff_x       - the offset into a_x[] for each auxiliary field
    1393: . a            - each auxiliary field evaluated at the current point
    1394: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1395: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1396: . t            - current time
    1397: . x            - coordinates of the current point
    1398: . numConstants - number of constant parameters
    1399: . constants    - constant parameters
    1400: - f0           - output values at the current point

    1402:   Level: intermediate

    1404:   Note:
    1405:   `f1` has an identical form and is omitted for brevity.

    1407:   We are using a first order FEM model for the weak form\: $  \int_\Omega \phi f_0(u, u_t, \nabla u, x, t) + \nabla\phi \cdot {\vec f}_1(u, u_t, \nabla u, x, t)$

    1409: .seealso: `PetscDS`, `PetscDSSetResidual()`
    1410: @*/
    1411: PetscErrorCode PetscDSGetResidual(PetscDS ds, PetscInt f, void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]), void (**f1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1412: {
    1413:   PetscPointFunc *tmp0, *tmp1;
    1414:   PetscInt        n0, n1;

    1416:   PetscFunctionBegin;
    1418:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    1419:   PetscCall(PetscWeakFormGetResidual(ds->wf, NULL, 0, f, 0, &n0, &tmp0, &n1, &tmp1));
    1420:   *f0 = tmp0 ? tmp0[0] : NULL;
    1421:   *f1 = tmp1 ? tmp1[0] : NULL;
    1422:   PetscFunctionReturn(PETSC_SUCCESS);
    1423: }

    1425: /*@C
    1426:   PetscDSSetResidual - Set the pointwise residual function for a given test field

    1428:   Not Collective

    1430:   Input Parameters:
    1431: + ds - The `PetscDS`
    1432: . f  - The test field number
    1433: . f0 - integrand for the test function term
    1434: - f1 - integrand for the test function gradient term

    1436:   Calling sequence of `f0`:
    1437: + dim          - the spatial dimension
    1438: . Nf           - the number of fields
    1439: . NfAux        - the number of auxiliary fields
    1440: . uOff         - the offset into u[] and u_t[] for each field
    1441: . uOff_x       - the offset into u_x[] for each field
    1442: . u            - each field evaluated at the current point
    1443: . u_t          - the time derivative of each field evaluated at the current point
    1444: . u_x          - the gradient of each field evaluated at the current point
    1445: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1446: . aOff_x       - the offset into a_x[] for each auxiliary field
    1447: . a            - each auxiliary field evaluated at the current point
    1448: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1449: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1450: . t            - current time
    1451: . x            - coordinates of the current point
    1452: . numConstants - number of constant parameters
    1453: . constants    - constant parameters
    1454: - f0           - output values at the current point

    1456:   Level: intermediate

    1458:   Note:
    1459:   `f1` has an identical form and is omitted for brevity.

    1461:   We are using a first order FEM model for the weak form\: $  \int_\Omega \phi f_0(u, u_t, \nabla u, x, t) + \nabla\phi \cdot {\vec f}_1(u, u_t, \nabla u, x, t)$

    1463: .seealso: `PetscDS`, `PetscDSGetResidual()`
    1464: @*/
    1465: PetscErrorCode PetscDSSetResidual(PetscDS ds, PetscInt f, void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]), void (*f1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1466: {
    1467:   PetscFunctionBegin;
    1471:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1472:   PetscCall(PetscWeakFormSetIndexResidual(ds->wf, NULL, 0, f, 0, 0, f0, 0, f1));
    1473:   PetscFunctionReturn(PETSC_SUCCESS);
    1474: }

    1476: /*@C
    1477:   PetscDSGetRHSResidual - Get the pointwise RHS residual function for explicit timestepping for a given test field

    1479:   Not Collective

    1481:   Input Parameters:
    1482: + ds - The `PetscDS`
    1483: - f  - The test field number

    1485:   Output Parameters:
    1486: + f0 - integrand for the test function term
    1487: - f1 - integrand for the test function gradient term

    1489:   Calling sequence of `f0`:
    1490: + dim          - the spatial dimension
    1491: . Nf           - the number of fields
    1492: . NfAux        - the number of auxiliary fields
    1493: . uOff         - the offset into u[] and u_t[] for each field
    1494: . uOff_x       - the offset into u_x[] for each field
    1495: . u            - each field evaluated at the current point
    1496: . u_t          - the time derivative of each field evaluated at the current point
    1497: . u_x          - the gradient of each field evaluated at the current point
    1498: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1499: . aOff_x       - the offset into a_x[] for each auxiliary field
    1500: . a            - each auxiliary field evaluated at the current point
    1501: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1502: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1503: . t            - current time
    1504: . x            - coordinates of the current point
    1505: . numConstants - number of constant parameters
    1506: . constants    - constant parameters
    1507: - f0           - output values at the current point

    1509:   Level: intermediate

    1511:   Note:
    1512:   `f1` has an identical form and is omitted for brevity.

    1514:   We are using a first order FEM model for the weak form\: $ \int_\Omega \phi f_0(u, u_t, \nabla u, x, t) + \nabla\phi \cdot {\vec f}_1(u, u_t, \nabla u, x, t)$

    1516: .seealso: `PetscDS`, `PetscDSSetRHSResidual()`
    1517: @*/
    1518: PetscErrorCode PetscDSGetRHSResidual(PetscDS ds, PetscInt f, void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]), void (**f1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1519: {
    1520:   PetscPointFunc *tmp0, *tmp1;
    1521:   PetscInt        n0, n1;

    1523:   PetscFunctionBegin;
    1525:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    1526:   PetscCall(PetscWeakFormGetResidual(ds->wf, NULL, 0, f, 100, &n0, &tmp0, &n1, &tmp1));
    1527:   *f0 = tmp0 ? tmp0[0] : NULL;
    1528:   *f1 = tmp1 ? tmp1[0] : NULL;
    1529:   PetscFunctionReturn(PETSC_SUCCESS);
    1530: }

    1532: /*@C
    1533:   PetscDSSetRHSResidual - Set the pointwise residual function for explicit timestepping for a given test field

    1535:   Not Collective

    1537:   Input Parameters:
    1538: + ds - The `PetscDS`
    1539: . f  - The test field number
    1540: . f0 - integrand for the test function term
    1541: - f1 - integrand for the test function gradient term

    1543:   Calling sequence for the callbacks `f0`:
    1544: + dim          - the spatial dimension
    1545: . Nf           - the number of fields
    1546: . NfAux        - the number of auxiliary fields
    1547: . uOff         - the offset into u[] and u_t[] for each field
    1548: . uOff_x       - the offset into u_x[] for each field
    1549: . u            - each field evaluated at the current point
    1550: . u_t          - the time derivative of each field evaluated at the current point
    1551: . u_x          - the gradient of each field evaluated at the current point
    1552: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1553: . aOff_x       - the offset into a_x[] for each auxiliary field
    1554: . a            - each auxiliary field evaluated at the current point
    1555: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1556: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1557: . t            - current time
    1558: . x            - coordinates of the current point
    1559: . numConstants - number of constant parameters
    1560: . constants    - constant parameters
    1561: - f0           - output values at the current point

    1563:   Level: intermediate

    1565:   Note:
    1566:   `f1` has an identical form and is omitted for brevity.

    1568:   We are using a first order FEM model for the weak form\: $ \int_\Omega \phi f_0(u, u_t, \nabla u, x, t) + \nabla\phi \cdot {\vec f}_1(u, u_t, \nabla u, x, t)$

    1570: .seealso: `PetscDS`, `PetscDSGetResidual()`
    1571: @*/
    1572: PetscErrorCode PetscDSSetRHSResidual(PetscDS ds, PetscInt f, void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]), void (*f1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1573: {
    1574:   PetscFunctionBegin;
    1578:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1579:   PetscCall(PetscWeakFormSetIndexResidual(ds->wf, NULL, 0, f, 100, 0, f0, 0, f1));
    1580:   PetscFunctionReturn(PETSC_SUCCESS);
    1581: }

    1583: /*@
    1584:   PetscDSHasJacobian - Checks that the Jacobian functions have been set

    1586:   Not Collective

    1588:   Input Parameter:
    1589: . ds - The `PetscDS`

    1591:   Output Parameter:
    1592: . hasJac - flag that pointwise function for the Jacobian has been set

    1594:   Level: intermediate

    1596: .seealso: `PetscDS`, `PetscDSGetJacobianPreconditioner()`, `PetscDSSetJacobianPreconditioner()`, `PetscDSGetJacobian()`
    1597: @*/
    1598: PetscErrorCode PetscDSHasJacobian(PetscDS ds, PetscBool *hasJac)
    1599: {
    1600:   PetscFunctionBegin;
    1602:   PetscCall(PetscWeakFormHasJacobian(ds->wf, hasJac));
    1603:   PetscFunctionReturn(PETSC_SUCCESS);
    1604: }

    1606: /*@C
    1607:   PetscDSGetJacobian - Get the pointwise Jacobian function for given test and basis field

    1609:   Not Collective

    1611:   Input Parameters:
    1612: + ds - The `PetscDS`
    1613: . f  - The test field number
    1614: - g  - The field number

    1616:   Output Parameters:
    1617: + g0 - integrand for the test and basis function term
    1618: . g1 - integrand for the test function and basis function gradient term
    1619: . g2 - integrand for the test function gradient and basis function term
    1620: - g3 - integrand for the test function gradient and basis function gradient term

    1622:   Calling sequence of `g0`:
    1623: + dim          - the spatial dimension
    1624: . Nf           - the number of fields
    1625: . NfAux        - the number of auxiliary fields
    1626: . uOff         - the offset into u[] and u_t[] for each field
    1627: . uOff_x       - the offset into u_x[] for each field
    1628: . u            - each field evaluated at the current point
    1629: . u_t          - the time derivative of each field evaluated at the current point
    1630: . u_x          - the gradient of each field evaluated at the current point
    1631: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1632: . aOff_x       - the offset into a_x[] for each auxiliary field
    1633: . a            - each auxiliary field evaluated at the current point
    1634: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1635: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1636: . t            - current time
    1637: . u_tShift     - the multiplier a for dF/dU_t
    1638: . x            - coordinates of the current point
    1639: . numConstants - number of constant parameters
    1640: . constants    - constant parameters
    1641: - g0           - output values at the current point

    1643:   Level: intermediate

    1645:   Note:
    1646:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    1648:   We are using a first order FEM model for the weak form\:

    1650:   $$
    1651:   \int_\Omega \phi\, g_0(u, u_t, \nabla u, x, t) \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \nabla \psi
    1652:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \nabla \psi
    1653:   $$

    1655: .seealso: `PetscDS`, `PetscDSSetJacobian()`
    1656: @*/
    1657: PetscErrorCode PetscDSGetJacobian(PetscDS ds, PetscInt f, PetscInt g, void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (**g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1658: {
    1659:   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    1660:   PetscInt       n0, n1, n2, n3;

    1662:   PetscFunctionBegin;
    1664:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    1665:   PetscCheck(!(g < 0) && !(g >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", g, ds->Nf);
    1666:   PetscCall(PetscWeakFormGetJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    1667:   *g0 = tmp0 ? tmp0[0] : NULL;
    1668:   *g1 = tmp1 ? tmp1[0] : NULL;
    1669:   *g2 = tmp2 ? tmp2[0] : NULL;
    1670:   *g3 = tmp3 ? tmp3[0] : NULL;
    1671:   PetscFunctionReturn(PETSC_SUCCESS);
    1672: }

    1674: /*@C
    1675:   PetscDSSetJacobian - Set the pointwise Jacobian function for given test and basis fields

    1677:   Not Collective

    1679:   Input Parameters:
    1680: + ds - The `PetscDS`
    1681: . f  - The test field number
    1682: . g  - The field number
    1683: . g0 - integrand for the test and basis function term
    1684: . g1 - integrand for the test function and basis function gradient term
    1685: . g2 - integrand for the test function gradient and basis function term
    1686: - g3 - integrand for the test function gradient and basis function gradient term

    1688:   Calling sequence of `g0`:
    1689: + dim          - the spatial dimension
    1690: . Nf           - the number of fields
    1691: . NfAux        - the number of auxiliary fields
    1692: . uOff         - the offset into u[] and u_t[] for each field
    1693: . uOff_x       - the offset into u_x[] for each field
    1694: . u            - each field evaluated at the current point
    1695: . u_t          - the time derivative of each field evaluated at the current point
    1696: . u_x          - the gradient of each field evaluated at the current point
    1697: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1698: . aOff_x       - the offset into a_x[] for each auxiliary field
    1699: . a            - each auxiliary field evaluated at the current point
    1700: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1701: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1702: . t            - current time
    1703: . u_tShift     - the multiplier a for dF/dU_t
    1704: . x            - coordinates of the current point
    1705: . numConstants - number of constant parameters
    1706: . constants    - constant parameters
    1707: - g0           - output values at the current point

    1709:   Level: intermediate

    1711:   Note:
    1712:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    1714:   We are using a first order FEM model for the weak form\:

    1716:   $$
    1717:   \int_\Omega \phi\, g_0(u, u_t, \nabla u, x, t) \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \nabla \psi
    1718:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \nabla \psi
    1719:   $$

    1721: .seealso: `PetscDS`, `PetscDSGetJacobian()`
    1722: @*/
    1723: PetscErrorCode PetscDSSetJacobian(PetscDS ds, PetscInt f, PetscInt g, void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (*g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1724: {
    1725:   PetscFunctionBegin;
    1731:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1732:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    1733:   PetscCall(PetscWeakFormSetIndexJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    1734:   PetscFunctionReturn(PETSC_SUCCESS);
    1735: }

    1737: /*@
    1738:   PetscDSUseJacobianPreconditioner - Set whether to construct a Jacobian preconditioner

    1740:   Not Collective

    1742:   Input Parameters:
    1743: + prob      - The `PetscDS`
    1744: - useJacPre - flag that enables construction of a Jacobian preconditioner

    1746:   Level: intermediate

    1748:   Developer Note:
    1749:   Should be called `PetscDSSetUseJacobianPreconditioner()`

    1751: .seealso: `PetscDS`, `PetscDSGetJacobianPreconditioner()`, `PetscDSSetJacobianPreconditioner()`, `PetscDSGetJacobian()`
    1752: @*/
    1753: PetscErrorCode PetscDSUseJacobianPreconditioner(PetscDS prob, PetscBool useJacPre)
    1754: {
    1755:   PetscFunctionBegin;
    1757:   prob->useJacPre = useJacPre;
    1758:   PetscFunctionReturn(PETSC_SUCCESS);
    1759: }

    1761: /*@
    1762:   PetscDSHasJacobianPreconditioner - Checks if a Jacobian preconditioner matrix has been set

    1764:   Not Collective

    1766:   Input Parameter:
    1767: . ds - The `PetscDS`

    1769:   Output Parameter:
    1770: . hasJacPre - flag that pointwise function for Jacobian preconditioner matrix has been set

    1772:   Level: intermediate

    1774: .seealso: `PetscDS`, `PetscDSGetJacobianPreconditioner()`, `PetscDSSetJacobianPreconditioner()`, `PetscDSGetJacobian()`
    1775: @*/
    1776: PetscErrorCode PetscDSHasJacobianPreconditioner(PetscDS ds, PetscBool *hasJacPre)
    1777: {
    1778:   PetscFunctionBegin;
    1780:   *hasJacPre = PETSC_FALSE;
    1781:   if (!ds->useJacPre) PetscFunctionReturn(PETSC_SUCCESS);
    1782:   PetscCall(PetscWeakFormHasJacobianPreconditioner(ds->wf, hasJacPre));
    1783:   PetscFunctionReturn(PETSC_SUCCESS);
    1784: }

    1786: /*@C
    1787:   PetscDSGetJacobianPreconditioner - Get the pointwise Jacobian preconditioner function for given test and basis field. If this is missing,
    1788:   the system matrix is used to build the preconditioner.

    1790:   Not Collective

    1792:   Input Parameters:
    1793: + ds - The `PetscDS`
    1794: . f  - The test field number
    1795: - g  - The field number

    1797:   Output Parameters:
    1798: + g0 - integrand for the test and basis function term
    1799: . g1 - integrand for the test function and basis function gradient term
    1800: . g2 - integrand for the test function gradient and basis function term
    1801: - g3 - integrand for the test function gradient and basis function gradient term

    1803:   Calling sequence of `g0`:
    1804: + dim          - the spatial dimension
    1805: . Nf           - the number of fields
    1806: . NfAux        - the number of auxiliary fields
    1807: . uOff         - the offset into u[] and u_t[] for each field
    1808: . uOff_x       - the offset into u_x[] for each field
    1809: . u            - each field evaluated at the current point
    1810: . u_t          - the time derivative of each field evaluated at the current point
    1811: . u_x          - the gradient of each field evaluated at the current point
    1812: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1813: . aOff_x       - the offset into a_x[] for each auxiliary field
    1814: . a            - each auxiliary field evaluated at the current point
    1815: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1816: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1817: . t            - current time
    1818: . u_tShift     - the multiplier a for dF/dU_t
    1819: . x            - coordinates of the current point
    1820: . numConstants - number of constant parameters
    1821: . constants    - constant parameters
    1822: - g0           - output values at the current point

    1824:   Level: intermediate

    1826:   Note:
    1827:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.
    1828:   We are using a first order FEM model for the weak form\:

    1830:   $$
    1831:   \int_\Omega \phi\, g_0(u, u_t, \nabla u, x, t) \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \nabla \psi
    1832:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \nabla \psi
    1833:   $$

    1835: .seealso: `PetscDS`, `PetscDSSetJacobianPreconditioner()`, `PetscDSGetJacobian()`
    1836: @*/
    1837: PetscErrorCode PetscDSGetJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g, void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (**g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1838: {
    1839:   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    1840:   PetscInt       n0, n1, n2, n3;

    1842:   PetscFunctionBegin;
    1844:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    1845:   PetscCheck(!(g < 0) && !(g >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", g, ds->Nf);
    1846:   PetscCall(PetscWeakFormGetJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    1847:   *g0 = tmp0 ? tmp0[0] : NULL;
    1848:   *g1 = tmp1 ? tmp1[0] : NULL;
    1849:   *g2 = tmp2 ? tmp2[0] : NULL;
    1850:   *g3 = tmp3 ? tmp3[0] : NULL;
    1851:   PetscFunctionReturn(PETSC_SUCCESS);
    1852: }

    1854: /*@C
    1855:   PetscDSSetJacobianPreconditioner - Set the pointwise Jacobian preconditioner function for given test and basis fields.
    1856:   If this is missing, the system matrix is used to build the preconditioner.

    1858:   Not Collective

    1860:   Input Parameters:
    1861: + ds - The `PetscDS`
    1862: . f  - The test field number
    1863: . g  - The field number
    1864: . g0 - integrand for the test and basis function term
    1865: . g1 - integrand for the test function and basis function gradient term
    1866: . g2 - integrand for the test function gradient and basis function term
    1867: - g3 - integrand for the test function gradient and basis function gradient term

    1869:   Calling sequence of `g0`:
    1870: + dim          - the spatial dimension
    1871: . Nf           - the number of fields
    1872: . NfAux        - the number of auxiliary fields
    1873: . uOff         - the offset into u[] and u_t[] for each field
    1874: . uOff_x       - the offset into u_x[] for each field
    1875: . u            - each field evaluated at the current point
    1876: . u_t          - the time derivative of each field evaluated at the current point
    1877: . u_x          - the gradient of each field evaluated at the current point
    1878: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1879: . aOff_x       - the offset into a_x[] for each auxiliary field
    1880: . a            - each auxiliary field evaluated at the current point
    1881: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1882: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1883: . t            - current time
    1884: . u_tShift     - the multiplier a for dF/dU_t
    1885: . x            - coordinates of the current point
    1886: . numConstants - number of constant parameters
    1887: . constants    - constant parameters
    1888: - g0           - output values at the current point

    1890:   Level: intermediate

    1892:   Note:
    1893:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    1895:   We are using a first order FEM model for the weak form\:

    1897:   $$
    1898:   \int_\Omega \phi\, g_0(u, u_t, \nabla u, x, t) \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \nabla \psi
    1899:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \nabla \psi
    1900:   $$

    1902: .seealso: `PetscDS`, `PetscDSGetJacobianPreconditioner()`, `PetscDSSetJacobian()`
    1903: @*/
    1904: PetscErrorCode PetscDSSetJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g, void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (*g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1905: {
    1906:   PetscFunctionBegin;
    1912:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1913:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    1914:   PetscCall(PetscWeakFormSetIndexJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    1915:   PetscFunctionReturn(PETSC_SUCCESS);
    1916: }

    1918: /*@
    1919:   PetscDSHasDynamicJacobian - Signals that a dynamic Jacobian, dF/du_t, has been set

    1921:   Not Collective

    1923:   Input Parameter:
    1924: . ds - The `PetscDS`

    1926:   Output Parameter:
    1927: . hasDynJac - flag that pointwise function for dynamic Jacobian has been set

    1929:   Level: intermediate

    1931: .seealso: `PetscDS`, `PetscDSGetDynamicJacobian()`, `PetscDSSetDynamicJacobian()`, `PetscDSGetJacobian()`
    1932: @*/
    1933: PetscErrorCode PetscDSHasDynamicJacobian(PetscDS ds, PetscBool *hasDynJac)
    1934: {
    1935:   PetscFunctionBegin;
    1937:   PetscCall(PetscWeakFormHasDynamicJacobian(ds->wf, hasDynJac));
    1938:   PetscFunctionReturn(PETSC_SUCCESS);
    1939: }

    1941: /*@C
    1942:   PetscDSGetDynamicJacobian - Get the pointwise dynamic Jacobian, dF/du_t, function for given test and basis field

    1944:   Not Collective

    1946:   Input Parameters:
    1947: + ds - The `PetscDS`
    1948: . f  - The test field number
    1949: - g  - The field number

    1951:   Output Parameters:
    1952: + g0 - integrand for the test and basis function term
    1953: . g1 - integrand for the test function and basis function gradient term
    1954: . g2 - integrand for the test function gradient and basis function term
    1955: - g3 - integrand for the test function gradient and basis function gradient term

    1957:   Calling sequence of `g0`:
    1958: + dim          - the spatial dimension
    1959: . Nf           - the number of fields
    1960: . NfAux        - the number of auxiliary fields
    1961: . uOff         - the offset into u[] and u_t[] for each field
    1962: . uOff_x       - the offset into u_x[] for each field
    1963: . u            - each field evaluated at the current point
    1964: . u_t          - the time derivative of each field evaluated at the current point
    1965: . u_x          - the gradient of each field evaluated at the current point
    1966: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    1967: . aOff_x       - the offset into a_x[] for each auxiliary field
    1968: . a            - each auxiliary field evaluated at the current point
    1969: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    1970: . a_x          - the gradient of auxiliary each field evaluated at the current point
    1971: . t            - current time
    1972: . u_tShift     - the multiplier a for dF/dU_t
    1973: . x            - coordinates of the current point
    1974: . numConstants - number of constant parameters
    1975: . constants    - constant parameters
    1976: - g0           - output values at the current point

    1978:   Level: intermediate

    1980:   Note:
    1981:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    1983:   We are using a first order FEM model for the weak form\:

    1985:   $$
    1986:   \int_\Omega \phi\, g_0(u, u_t, \nabla u, x, t) \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \nabla \psi
    1987:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \nabla \psi
    1988:   $$

    1990: .seealso: `PetscDS`, `PetscDSSetJacobian()`
    1991: @*/
    1992: PetscErrorCode PetscDSGetDynamicJacobian(PetscDS ds, PetscInt f, PetscInt g, void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (**g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    1993: {
    1994:   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    1995:   PetscInt       n0, n1, n2, n3;

    1997:   PetscFunctionBegin;
    1999:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    2000:   PetscCheck(!(g < 0) && !(g >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", g, ds->Nf);
    2001:   PetscCall(PetscWeakFormGetDynamicJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    2002:   *g0 = tmp0 ? tmp0[0] : NULL;
    2003:   *g1 = tmp1 ? tmp1[0] : NULL;
    2004:   *g2 = tmp2 ? tmp2[0] : NULL;
    2005:   *g3 = tmp3 ? tmp3[0] : NULL;
    2006:   PetscFunctionReturn(PETSC_SUCCESS);
    2007: }

    2009: /*@C
    2010:   PetscDSSetDynamicJacobian - Set the pointwise dynamic Jacobian, dF/du_t, function for given test and basis fields

    2012:   Not Collective

    2014:   Input Parameters:
    2015: + ds - The `PetscDS`
    2016: . f  - The test field number
    2017: . g  - The field number
    2018: . g0 - integrand for the test and basis function term
    2019: . g1 - integrand for the test function and basis function gradient term
    2020: . g2 - integrand for the test function gradient and basis function term
    2021: - g3 - integrand for the test function gradient and basis function gradient term

    2023:   Calling sequence of `g0`:
    2024: + dim          - the spatial dimension
    2025: . Nf           - the number of fields
    2026: . NfAux        - the number of auxiliary fields
    2027: . uOff         - the offset into u[] and u_t[] for each field
    2028: . uOff_x       - the offset into u_x[] for each field
    2029: . u            - each field evaluated at the current point
    2030: . u_t          - the time derivative of each field evaluated at the current point
    2031: . u_x          - the gradient of each field evaluated at the current point
    2032: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2033: . aOff_x       - the offset into a_x[] for each auxiliary field
    2034: . a            - each auxiliary field evaluated at the current point
    2035: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2036: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2037: . t            - current time
    2038: . u_tShift     - the multiplier a for dF/dU_t
    2039: . x            - coordinates of the current point
    2040: . numConstants - number of constant parameters
    2041: . constants    - constant parameters
    2042: - g0           - output values at the current point

    2044:   Level: intermediate

    2046:   Note:
    2047:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    2049:   We are using a first order FEM model for the weak form\:

    2051:   $$
    2052:   \int_\Omega \phi\, g_0(u, u_t, \nabla u, x, t) \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \nabla \psi
    2053:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \nabla \psi
    2054:   $$

    2056: .seealso: `PetscDS`, `PetscDSGetJacobian()`
    2057: @*/
    2058: PetscErrorCode PetscDSSetDynamicJacobian(PetscDS ds, PetscInt f, PetscInt g, void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (*g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    2059: {
    2060:   PetscFunctionBegin;
    2066:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2067:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    2068:   PetscCall(PetscWeakFormSetIndexDynamicJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    2069:   PetscFunctionReturn(PETSC_SUCCESS);
    2070: }

    2072: /*@C
    2073:   PetscDSGetRiemannSolver - Returns the Riemann solver for the given field

    2075:   Not Collective

    2077:   Input Parameters:
    2078: + ds - The `PetscDS` object
    2079: - f  - The field number

    2081:   Output Parameter:
    2082: . r - Riemann solver

    2084:   Calling sequence of `r`:
    2085: + dim          - The spatial dimension
    2086: . Nf           - The number of fields
    2087: . x            - The coordinates at a point on the interface
    2088: . n            - The normal vector to the interface
    2089: . uL           - The state vector to the left of the interface
    2090: . uR           - The state vector to the right of the interface
    2091: . flux         - output array of flux through the interface
    2092: . numConstants - number of constant parameters
    2093: . constants    - constant parameters
    2094: - ctx          - optional user context

    2096:   Level: intermediate

    2098: .seealso: `PetscDS`, `PetscDSSetRiemannSolver()`
    2099: @*/
    2100: PetscErrorCode PetscDSGetRiemannSolver(PetscDS ds, PetscInt f, void (**r)(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscInt numConstants, const PetscScalar constants[], PetscScalar flux[], void *ctx))
    2101: {
    2102:   PetscRiemannFunc *tmp;
    2103:   PetscInt          n;

    2105:   PetscFunctionBegin;
    2107:   PetscAssertPointer(r, 3);
    2108:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    2109:   PetscCall(PetscWeakFormGetRiemannSolver(ds->wf, NULL, 0, f, 0, &n, &tmp));
    2110:   *r = tmp ? tmp[0] : NULL;
    2111:   PetscFunctionReturn(PETSC_SUCCESS);
    2112: }

    2114: /*@C
    2115:   PetscDSSetRiemannSolver - Sets the Riemann solver for the given field

    2117:   Not Collective

    2119:   Input Parameters:
    2120: + ds - The `PetscDS` object
    2121: . f  - The field number
    2122: - r  - Riemann solver

    2124:   Calling sequence of `r`:
    2125: + dim          - The spatial dimension
    2126: . Nf           - The number of fields
    2127: . x            - The coordinates at a point on the interface
    2128: . n            - The normal vector to the interface
    2129: . uL           - The state vector to the left of the interface
    2130: . uR           - The state vector to the right of the interface
    2131: . flux         - output array of flux through the interface
    2132: . numConstants - number of constant parameters
    2133: . constants    - constant parameters
    2134: - ctx          - optional user context

    2136:   Level: intermediate

    2138: .seealso: `PetscDS`, `PetscDSGetRiemannSolver()`
    2139: @*/
    2140: PetscErrorCode PetscDSSetRiemannSolver(PetscDS ds, PetscInt f, void (*r)(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscInt numConstants, const PetscScalar constants[], PetscScalar flux[], void *ctx))
    2141: {
    2142:   PetscFunctionBegin;
    2145:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2146:   PetscCall(PetscWeakFormSetIndexRiemannSolver(ds->wf, NULL, 0, f, 0, 0, r));
    2147:   PetscFunctionReturn(PETSC_SUCCESS);
    2148: }

    2150: /*@C
    2151:   PetscDSGetUpdate - Get the pointwise update function for a given field

    2153:   Not Collective

    2155:   Input Parameters:
    2156: + ds - The `PetscDS`
    2157: - f  - The field number

    2159:   Output Parameter:
    2160: . update - update function

    2162:   Calling sequence of `update`:
    2163: + dim          - the spatial dimension
    2164: . Nf           - the number of fields
    2165: . NfAux        - the number of auxiliary fields
    2166: . uOff         - the offset into u[] and u_t[] for each field
    2167: . uOff_x       - the offset into u_x[] for each field
    2168: . u            - each field evaluated at the current point
    2169: . u_t          - the time derivative of each field evaluated at the current point
    2170: . u_x          - the gradient of each field evaluated at the current point
    2171: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2172: . aOff_x       - the offset into a_x[] for each auxiliary field
    2173: . a            - each auxiliary field evaluated at the current point
    2174: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2175: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2176: . t            - current time
    2177: . x            - coordinates of the current point
    2178: . numConstants - number of constant parameters
    2179: . constants    - constant parameters
    2180: - uNew         - new value for field at the current point

    2182:   Level: intermediate

    2184: .seealso: `PetscDS`, `PetscDSSetUpdate()`, `PetscDSSetResidual()`
    2185: @*/
    2186: PetscErrorCode PetscDSGetUpdate(PetscDS ds, PetscInt f, void (**update)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
    2187: {
    2188:   PetscFunctionBegin;
    2190:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    2191:   if (update) {
    2192:     PetscAssertPointer(update, 3);
    2193:     *update = ds->update[f];
    2194:   }
    2195:   PetscFunctionReturn(PETSC_SUCCESS);
    2196: }

    2198: /*@C
    2199:   PetscDSSetUpdate - Set the pointwise update function for a given field

    2201:   Not Collective

    2203:   Input Parameters:
    2204: + ds     - The `PetscDS`
    2205: . f      - The field number
    2206: - update - update function

    2208:   Calling sequence of `update`:
    2209: + dim          - the spatial dimension
    2210: . Nf           - the number of fields
    2211: . NfAux        - the number of auxiliary fields
    2212: . uOff         - the offset into u[] and u_t[] for each field
    2213: . uOff_x       - the offset into u_x[] for each field
    2214: . u            - each field evaluated at the current point
    2215: . u_t          - the time derivative of each field evaluated at the current point
    2216: . u_x          - the gradient of each field evaluated at the current point
    2217: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2218: . aOff_x       - the offset into a_x[] for each auxiliary field
    2219: . a            - each auxiliary field evaluated at the current point
    2220: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2221: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2222: . t            - current time
    2223: . x            - coordinates of the current point
    2224: . numConstants - number of constant parameters
    2225: . constants    - constant parameters
    2226: - uNew         - new field values at the current point

    2228:   Level: intermediate

    2230: .seealso: `PetscDS`, `PetscDSGetResidual()`
    2231: @*/
    2232: PetscErrorCode PetscDSSetUpdate(PetscDS ds, PetscInt f, void (*update)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
    2233: {
    2234:   PetscFunctionBegin;
    2237:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2238:   PetscCall(PetscDSEnlarge_Static(ds, f + 1));
    2239:   ds->update[f] = update;
    2240:   PetscFunctionReturn(PETSC_SUCCESS);
    2241: }

    2243: PetscErrorCode PetscDSGetContext(PetscDS ds, PetscInt f, void *ctx)
    2244: {
    2245:   PetscFunctionBegin;
    2247:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    2248:   PetscAssertPointer(ctx, 3);
    2249:   *(void **)ctx = ds->ctx[f];
    2250:   PetscFunctionReturn(PETSC_SUCCESS);
    2251: }

    2253: PetscErrorCode PetscDSSetContext(PetscDS ds, PetscInt f, void *ctx)
    2254: {
    2255:   PetscFunctionBegin;
    2257:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2258:   PetscCall(PetscDSEnlarge_Static(ds, f + 1));
    2259:   ds->ctx[f] = ctx;
    2260:   PetscFunctionReturn(PETSC_SUCCESS);
    2261: }

    2263: /*@C
    2264:   PetscDSGetBdResidual - Get the pointwise boundary residual function for a given test field

    2266:   Not Collective

    2268:   Input Parameters:
    2269: + ds - The PetscDS
    2270: - f  - The test field number

    2272:   Output Parameters:
    2273: + f0 - boundary integrand for the test function term
    2274: - f1 - boundary integrand for the test function gradient term

    2276:   Calling sequence of `f0`:
    2277: + dim          - the spatial dimension
    2278: . Nf           - the number of fields
    2279: . NfAux        - the number of auxiliary fields
    2280: . uOff         - the offset into u[] and u_t[] for each field
    2281: . uOff_x       - the offset into u_x[] for each field
    2282: . u            - each field evaluated at the current point
    2283: . u_t          - the time derivative of each field evaluated at the current point
    2284: . u_x          - the gradient of each field evaluated at the current point
    2285: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2286: . aOff_x       - the offset into a_x[] for each auxiliary field
    2287: . a            - each auxiliary field evaluated at the current point
    2288: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2289: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2290: . t            - current time
    2291: . x            - coordinates of the current point
    2292: . n            - unit normal at the current point
    2293: . numConstants - number of constant parameters
    2294: . constants    - constant parameters
    2295: - f0           - output values at the current point

    2297:   Level: intermediate

    2299:   Note:
    2300:   The calling sequence of `f1` is identical, and therefore omitted for brevity.

    2302:   We are using a first order FEM model for the weak form\:

    2304:   $$
    2305:   \int_\Gamma \phi {\vec f}_0(u, u_t, \nabla u, x, t) \cdot \hat n + \nabla\phi \cdot {\overleftrightarrow f}_1(u, u_t, \nabla u, x, t) \cdot \hat n
    2306:   $$

    2308: .seealso: `PetscDS`, `PetscDSSetBdResidual()`
    2309: @*/
    2310: PetscErrorCode PetscDSGetBdResidual(PetscDS ds, PetscInt f, void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]), void (**f1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    2311: {
    2312:   PetscBdPointFunc *tmp0, *tmp1;
    2313:   PetscInt          n0, n1;

    2315:   PetscFunctionBegin;
    2317:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    2318:   PetscCall(PetscWeakFormGetBdResidual(ds->wf, NULL, 0, f, 0, &n0, &tmp0, &n1, &tmp1));
    2319:   *f0 = tmp0 ? tmp0[0] : NULL;
    2320:   *f1 = tmp1 ? tmp1[0] : NULL;
    2321:   PetscFunctionReturn(PETSC_SUCCESS);
    2322: }

    2324: /*@C
    2325:   PetscDSSetBdResidual - Get the pointwise boundary residual function for a given test field

    2327:   Not Collective

    2329:   Input Parameters:
    2330: + ds - The `PetscDS`
    2331: . f  - The test field number
    2332: . f0 - boundary integrand for the test function term
    2333: - f1 - boundary integrand for the test function gradient term

    2335:   Calling sequence of `f0`:
    2336: + dim          - the spatial dimension
    2337: . Nf           - the number of fields
    2338: . NfAux        - the number of auxiliary fields
    2339: . uOff         - the offset into u[] and u_t[] for each field
    2340: . uOff_x       - the offset into u_x[] for each field
    2341: . u            - each field evaluated at the current point
    2342: . u_t          - the time derivative of each field evaluated at the current point
    2343: . u_x          - the gradient of each field evaluated at the current point
    2344: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2345: . aOff_x       - the offset into a_x[] for each auxiliary field
    2346: . a            - each auxiliary field evaluated at the current point
    2347: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2348: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2349: . t            - current time
    2350: . x            - coordinates of the current point
    2351: . n            - unit normal at the current point
    2352: . numConstants - number of constant parameters
    2353: . constants    - constant parameters
    2354: - f0           - output values at the current point

    2356:   Level: intermediate

    2358:   Note:
    2359:   The calling sequence of `f1` is identical, and therefore omitted for brevity.

    2361:   We are using a first order FEM model for the weak form\:

    2363:   $$
    2364:   \int_\Gamma \phi {\vec f}_0(u, u_t, \nabla u, x, t) \cdot \hat n + \nabla\phi \cdot {\overleftrightarrow f}_1(u, u_t, \nabla u, x, t) \cdot \hat n
    2365:   $$

    2367: .seealso: `PetscDS`, `PetscDSGetBdResidual()`
    2368: @*/
    2369: PetscErrorCode PetscDSSetBdResidual(PetscDS ds, PetscInt f, void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]), void (*f1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    2370: {
    2371:   PetscFunctionBegin;
    2373:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2374:   PetscCall(PetscWeakFormSetIndexBdResidual(ds->wf, NULL, 0, f, 0, 0, f0, 0, f1));
    2375:   PetscFunctionReturn(PETSC_SUCCESS);
    2376: }

    2378: /*@
    2379:   PetscDSHasBdJacobian - Indicates that boundary Jacobian functions have been set

    2381:   Not Collective

    2383:   Input Parameter:
    2384: . ds - The `PetscDS`

    2386:   Output Parameter:
    2387: . hasBdJac - flag that pointwise function for the boundary Jacobian has been set

    2389:   Level: intermediate

    2391: .seealso: `PetscDS`, `PetscDSHasJacobian()`, `PetscDSSetBdJacobian()`, `PetscDSGetBdJacobian()`
    2392: @*/
    2393: PetscErrorCode PetscDSHasBdJacobian(PetscDS ds, PetscBool *hasBdJac)
    2394: {
    2395:   PetscFunctionBegin;
    2397:   PetscAssertPointer(hasBdJac, 2);
    2398:   PetscCall(PetscWeakFormHasBdJacobian(ds->wf, hasBdJac));
    2399:   PetscFunctionReturn(PETSC_SUCCESS);
    2400: }

    2402: /*@C
    2403:   PetscDSGetBdJacobian - Get the pointwise boundary Jacobian function for given test and basis field

    2405:   Not Collective

    2407:   Input Parameters:
    2408: + ds - The `PetscDS`
    2409: . f  - The test field number
    2410: - g  - The field number

    2412:   Output Parameters:
    2413: + g0 - integrand for the test and basis function term
    2414: . g1 - integrand for the test function and basis function gradient term
    2415: . g2 - integrand for the test function gradient and basis function term
    2416: - g3 - integrand for the test function gradient and basis function gradient term

    2418:   Calling sequence of `g0`:
    2419: + dim          - the spatial dimension
    2420: . Nf           - the number of fields
    2421: . NfAux        - the number of auxiliary fields
    2422: . uOff         - the offset into u[] and u_t[] for each field
    2423: . uOff_x       - the offset into u_x[] for each field
    2424: . u            - each field evaluated at the current point
    2425: . u_t          - the time derivative of each field evaluated at the current point
    2426: . u_x          - the gradient of each field evaluated at the current point
    2427: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2428: . aOff_x       - the offset into a_x[] for each auxiliary field
    2429: . a            - each auxiliary field evaluated at the current point
    2430: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2431: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2432: . t            - current time
    2433: . u_tShift     - the multiplier a for dF/dU_t
    2434: . x            - coordinates of the current point
    2435: . n            - normal at the current point
    2436: . numConstants - number of constant parameters
    2437: . constants    - constant parameters
    2438: - g0           - output values at the current point

    2440:   Level: intermediate

    2442:   Note:
    2443:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    2445:   We are using a first order FEM model for the weak form\:

    2447:   $$
    2448:   \int_\Gamma \phi\, {\vec g}_0(u, u_t, \nabla u, x, t) \cdot \hat n \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \cdot \hat n \nabla \psi
    2449:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \cdot \hat n \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \hat n \cdot \nabla \psi
    2450:   $$

    2452: .seealso: `PetscDS`, `PetscDSSetBdJacobian()`
    2453: @*/
    2454: PetscErrorCode PetscDSGetBdJacobian(PetscDS ds, PetscInt f, PetscInt g, void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (**g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    2455: {
    2456:   PetscBdPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    2457:   PetscInt         n0, n1, n2, n3;

    2459:   PetscFunctionBegin;
    2461:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    2462:   PetscCheck(!(g < 0) && !(g >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", g, ds->Nf);
    2463:   PetscCall(PetscWeakFormGetBdJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    2464:   *g0 = tmp0 ? tmp0[0] : NULL;
    2465:   *g1 = tmp1 ? tmp1[0] : NULL;
    2466:   *g2 = tmp2 ? tmp2[0] : NULL;
    2467:   *g3 = tmp3 ? tmp3[0] : NULL;
    2468:   PetscFunctionReturn(PETSC_SUCCESS);
    2469: }

    2471: /*@C
    2472:   PetscDSSetBdJacobian - Set the pointwise boundary Jacobian function for given test and basis field

    2474:   Not Collective

    2476:   Input Parameters:
    2477: + ds - The PetscDS
    2478: . f  - The test field number
    2479: . g  - The field number
    2480: . g0 - integrand for the test and basis function term
    2481: . g1 - integrand for the test function and basis function gradient term
    2482: . g2 - integrand for the test function gradient and basis function term
    2483: - g3 - integrand for the test function gradient and basis function gradient term

    2485:   Calling sequence of `g0`:
    2486: + dim          - the spatial dimension
    2487: . Nf           - the number of fields
    2488: . NfAux        - the number of auxiliary fields
    2489: . uOff         - the offset into u[] and u_t[] for each field
    2490: . uOff_x       - the offset into u_x[] for each field
    2491: . u            - each field evaluated at the current point
    2492: . u_t          - the time derivative of each field evaluated at the current point
    2493: . u_x          - the gradient of each field evaluated at the current point
    2494: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2495: . aOff_x       - the offset into a_x[] for each auxiliary field
    2496: . a            - each auxiliary field evaluated at the current point
    2497: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2498: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2499: . t            - current time
    2500: . u_tShift     - the multiplier a for dF/dU_t
    2501: . x            - coordinates of the current point
    2502: . n            - normal at the current point
    2503: . numConstants - number of constant parameters
    2504: . constants    - constant parameters
    2505: - g0           - output values at the current point

    2507:   Level: intermediate

    2509:   Note:
    2510:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    2512:   We are using a first order FEM model for the weak form\:

    2514:   $$
    2515:   \int_\Gamma \phi\, {\vec g}_0(u, u_t, \nabla u, x, t) \cdot \hat n \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \cdot \hat n \nabla \psi
    2516:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \cdot \hat n \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \hat n \cdot \nabla \psi
    2517:   $$

    2519: .seealso: `PetscDS`, `PetscDSGetBdJacobian()`
    2520: @*/
    2521: PetscErrorCode PetscDSSetBdJacobian(PetscDS ds, PetscInt f, PetscInt g, void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (*g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    2522: {
    2523:   PetscFunctionBegin;
    2529:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2530:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    2531:   PetscCall(PetscWeakFormSetIndexBdJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    2532:   PetscFunctionReturn(PETSC_SUCCESS);
    2533: }

    2535: /*@
    2536:   PetscDSHasBdJacobianPreconditioner - Signals that boundary Jacobian preconditioner functions have been set

    2538:   Not Collective

    2540:   Input Parameter:
    2541: . ds - The `PetscDS`

    2543:   Output Parameter:
    2544: . hasBdJacPre - flag that pointwise function for the boundary Jacobian preconditioner has been set

    2546:   Level: intermediate

    2548: .seealso: `PetscDS`, `PetscDSHasJacobian()`, `PetscDSSetBdJacobian()`, `PetscDSGetBdJacobian()`
    2549: @*/
    2550: PetscErrorCode PetscDSHasBdJacobianPreconditioner(PetscDS ds, PetscBool *hasBdJacPre)
    2551: {
    2552:   PetscFunctionBegin;
    2554:   PetscAssertPointer(hasBdJacPre, 2);
    2555:   PetscCall(PetscWeakFormHasBdJacobianPreconditioner(ds->wf, hasBdJacPre));
    2556:   PetscFunctionReturn(PETSC_SUCCESS);
    2557: }

    2559: /*@C
    2560:   PetscDSGetBdJacobianPreconditioner - Get the pointwise boundary Jacobian preconditioner function for given test and basis field

    2562:   Not Collective; No Fortran Support

    2564:   Input Parameters:
    2565: + ds - The `PetscDS`
    2566: . f  - The test field number
    2567: - g  - The field number

    2569:   Output Parameters:
    2570: + g0 - integrand for the test and basis function term
    2571: . g1 - integrand for the test function and basis function gradient term
    2572: . g2 - integrand for the test function gradient and basis function term
    2573: - g3 - integrand for the test function gradient and basis function gradient term

    2575:   Calling sequence of `g0`:
    2576: + dim          - the spatial dimension
    2577: . Nf           - the number of fields
    2578: . NfAux        - the number of auxiliary fields
    2579: . uOff         - the offset into u[] and u_t[] for each field
    2580: . uOff_x       - the offset into u_x[] for each field
    2581: . u            - each field evaluated at the current point
    2582: . u_t          - the time derivative of each field evaluated at the current point
    2583: . u_x          - the gradient of each field evaluated at the current point
    2584: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2585: . aOff_x       - the offset into a_x[] for each auxiliary field
    2586: . a            - each auxiliary field evaluated at the current point
    2587: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2588: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2589: . t            - current time
    2590: . u_tShift     - the multiplier a for dF/dU_t
    2591: . x            - coordinates of the current point
    2592: . n            - normal at the current point
    2593: . numConstants - number of constant parameters
    2594: . constants    - constant parameters
    2595: - g0           - output values at the current point

    2597:   Level: intermediate

    2599:   Note:
    2600:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    2602:   We are using a first order FEM model for the weak form\:

    2604:   $$
    2605:   \int_\Gamma \phi\, {\vec g}_0(u, u_t, \nabla u, x, t) \cdot \hat n \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \cdot \hat n \nabla \psi
    2606:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \cdot \hat n \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \hat n \cdot \nabla \psi
    2607:   $$

    2609: .seealso: `PetscDS`, `PetscDSSetBdJacobianPreconditioner()`
    2610: @*/
    2611: PetscErrorCode PetscDSGetBdJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g, void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (**g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (**g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    2612: {
    2613:   PetscBdPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    2614:   PetscInt         n0, n1, n2, n3;

    2616:   PetscFunctionBegin;
    2618:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    2619:   PetscCheck(!(g < 0) && !(g >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", g, ds->Nf);
    2620:   PetscCall(PetscWeakFormGetBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    2621:   *g0 = tmp0 ? tmp0[0] : NULL;
    2622:   *g1 = tmp1 ? tmp1[0] : NULL;
    2623:   *g2 = tmp2 ? tmp2[0] : NULL;
    2624:   *g3 = tmp3 ? tmp3[0] : NULL;
    2625:   PetscFunctionReturn(PETSC_SUCCESS);
    2626: }

    2628: /*@C
    2629:   PetscDSSetBdJacobianPreconditioner - Set the pointwise boundary Jacobian preconditioner function for given test and basis field

    2631:   Not Collective; No Fortran Support

    2633:   Input Parameters:
    2634: + ds - The `PetscDS`
    2635: . f  - The test field number
    2636: . g  - The field number
    2637: . g0 - integrand for the test and basis function term
    2638: . g1 - integrand for the test function and basis function gradient term
    2639: . g2 - integrand for the test function gradient and basis function term
    2640: - g3 - integrand for the test function gradient and basis function gradient term

    2642:   Calling sequence of `g0':
    2643: + dim          - the spatial dimension
    2644: . Nf           - the number of fields
    2645: . NfAux        - the number of auxiliary fields
    2646: . uOff         - the offset into u[] and u_t[] for each field
    2647: . uOff_x       - the offset into u_x[] for each field
    2648: . u            - each field evaluated at the current point
    2649: . u_t          - the time derivative of each field evaluated at the current point
    2650: . u_x          - the gradient of each field evaluated at the current point
    2651: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    2652: . aOff_x       - the offset into a_x[] for each auxiliary field
    2653: . a            - each auxiliary field evaluated at the current point
    2654: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    2655: . a_x          - the gradient of auxiliary each field evaluated at the current point
    2656: . t            - current time
    2657: . u_tShift     - the multiplier a for dF/dU_t
    2658: . x            - coordinates of the current point
    2659: . n            - normal at the current point
    2660: . numConstants - number of constant parameters
    2661: . constants    - constant parameters
    2662: - g0           - output values at the current point

    2664:   Level: intermediate

    2666:   Note:
    2667:   `g1`, `g2`, and `g3` have identical calling sequences to `g0` and are omitted for brevity.

    2669:   We are using a first order FEM model for the weak form\:

    2671:   $$
    2672:   \int_\Gamma \phi\, {\vec g}_0(u, u_t, \nabla u, x, t) \cdot \hat n \psi + \phi\, {\vec g}_1(u, u_t, \nabla u, x, t) \cdot \hat n \nabla \psi
    2673:   + \nabla\phi \cdot {\vec g}_2(u, u_t, \nabla u, x, t) \cdot \hat n \psi + \nabla\phi \cdot {\overleftrightarrow g}_3(u, u_t, \nabla u, x, t) \cdot \hat n \cdot \nabla \psi
    2674:   $$

    2676: .seealso: `PetscDS`, `PetscDSGetBdJacobianPreconditioner()`
    2677: @*/
    2678: PetscErrorCode PetscDSSetBdJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g, void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]), void (*g1)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g2)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void (*g3)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]))
    2679: {
    2680:   PetscFunctionBegin;
    2686:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2687:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    2688:   PetscCall(PetscWeakFormSetIndexBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    2689:   PetscFunctionReturn(PETSC_SUCCESS);
    2690: }

    2692: /*@C
    2693:   PetscDSGetExactSolution - Get the pointwise exact solution function for a given test field

    2695:   Not Collective

    2697:   Input Parameters:
    2698: + prob - The PetscDS
    2699: - f    - The test field number

    2701:   Output Parameters:
    2702: + sol - exact solution for the test field
    2703: - ctx - exact solution context

    2705:   Calling sequence of `exactSol`:
    2706: + dim - the spatial dimension
    2707: . t   - current time
    2708: . x   - coordinates of the current point
    2709: . Nc  - the number of field components
    2710: . u   - the solution field evaluated at the current point
    2711: - ctx - a user context

    2713:   Level: intermediate

    2715: .seealso: `PetscDS`, `PetscDSSetExactSolution()`, `PetscDSGetExactSolutionTimeDerivative()`
    2716: @*/
    2717: PetscErrorCode PetscDSGetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
    2718: {
    2719:   PetscFunctionBegin;
    2721:   PetscCheck(!(f < 0) && !(f >= prob->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, prob->Nf);
    2722:   if (sol) {
    2723:     PetscAssertPointer(sol, 3);
    2724:     *sol = prob->exactSol[f];
    2725:   }
    2726:   if (ctx) {
    2727:     PetscAssertPointer(ctx, 4);
    2728:     *ctx = prob->exactCtx[f];
    2729:   }
    2730:   PetscFunctionReturn(PETSC_SUCCESS);
    2731: }

    2733: /*@C
    2734:   PetscDSSetExactSolution - Set the pointwise exact solution function for a given test field

    2736:   Not Collective

    2738:   Input Parameters:
    2739: + prob - The `PetscDS`
    2740: . f    - The test field number
    2741: . sol  - solution function for the test fields
    2742: - ctx  - solution context or `NULL`

    2744:   Calling sequence of `sol`:
    2745: + dim - the spatial dimension
    2746: . t   - current time
    2747: . x   - coordinates of the current point
    2748: . Nc  - the number of field components
    2749: . u   - the solution field evaluated at the current point
    2750: - ctx - a user context

    2752:   Level: intermediate

    2754: .seealso: `PetscDS`, `PetscDSGetExactSolution()`
    2755: @*/
    2756: PetscErrorCode PetscDSSetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
    2757: {
    2758:   PetscFunctionBegin;
    2760:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2761:   PetscCall(PetscDSEnlarge_Static(prob, f + 1));
    2762:   if (sol) {
    2764:     prob->exactSol[f] = sol;
    2765:   }
    2766:   if (ctx) {
    2768:     prob->exactCtx[f] = ctx;
    2769:   }
    2770:   PetscFunctionReturn(PETSC_SUCCESS);
    2771: }

    2773: /*@C
    2774:   PetscDSGetExactSolutionTimeDerivative - Get the pointwise time derivative of the exact solution function for a given test field

    2776:   Not Collective

    2778:   Input Parameters:
    2779: + prob - The `PetscDS`
    2780: - f    - The test field number

    2782:   Output Parameters:
    2783: + sol - time derivative of the exact solution for the test field
    2784: - ctx - time derivative of the exact solution context

    2786:   Calling sequence of `exactSol`:
    2787: + dim - the spatial dimension
    2788: . t   - current time
    2789: . x   - coordinates of the current point
    2790: . Nc  - the number of field components
    2791: . u   - the solution field evaluated at the current point
    2792: - ctx - a user context

    2794:   Level: intermediate

    2796: .seealso: `PetscDS`, `PetscDSSetExactSolutionTimeDerivative()`, `PetscDSGetExactSolution()`
    2797: @*/
    2798: PetscErrorCode PetscDSGetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
    2799: {
    2800:   PetscFunctionBegin;
    2802:   PetscCheck(!(f < 0) && !(f >= prob->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, prob->Nf);
    2803:   if (sol) {
    2804:     PetscAssertPointer(sol, 3);
    2805:     *sol = prob->exactSol_t[f];
    2806:   }
    2807:   if (ctx) {
    2808:     PetscAssertPointer(ctx, 4);
    2809:     *ctx = prob->exactCtx_t[f];
    2810:   }
    2811:   PetscFunctionReturn(PETSC_SUCCESS);
    2812: }

    2814: /*@C
    2815:   PetscDSSetExactSolutionTimeDerivative - Set the pointwise time derivative of the exact solution function for a given test field

    2817:   Not Collective

    2819:   Input Parameters:
    2820: + prob - The `PetscDS`
    2821: . f    - The test field number
    2822: . sol  - time derivative of the solution function for the test fields
    2823: - ctx  - time derivative of the solution context or `NULL`

    2825:   Calling sequence of `sol`:
    2826: + dim - the spatial dimension
    2827: . t   - current time
    2828: . x   - coordinates of the current point
    2829: . Nc  - the number of field components
    2830: . u   - the solution field evaluated at the current point
    2831: - ctx - a user context

    2833:   Level: intermediate

    2835: .seealso: `PetscDS`, `PetscDSGetExactSolutionTimeDerivative()`, `PetscDSSetExactSolution()`
    2836: @*/
    2837: PetscErrorCode PetscDSSetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
    2838: {
    2839:   PetscFunctionBegin;
    2841:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2842:   PetscCall(PetscDSEnlarge_Static(prob, f + 1));
    2843:   if (sol) {
    2845:     prob->exactSol_t[f] = sol;
    2846:   }
    2847:   if (ctx) {
    2849:     prob->exactCtx_t[f] = ctx;
    2850:   }
    2851:   PetscFunctionReturn(PETSC_SUCCESS);
    2852: }

    2854: /*@C
    2855:   PetscDSGetConstants - Returns the array of constants passed to point functions

    2857:   Not Collective

    2859:   Input Parameter:
    2860: . ds - The `PetscDS` object

    2862:   Output Parameters:
    2863: + numConstants - The number of constants
    2864: - constants    - The array of constants, NULL if there are none

    2866:   Level: intermediate

    2868: .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSCreate()`
    2869: @*/
    2870: PetscErrorCode PetscDSGetConstants(PetscDS ds, PetscInt *numConstants, const PetscScalar *constants[])
    2871: {
    2872:   PetscFunctionBegin;
    2874:   if (numConstants) {
    2875:     PetscAssertPointer(numConstants, 2);
    2876:     *numConstants = ds->numConstants;
    2877:   }
    2878:   if (constants) {
    2879:     PetscAssertPointer(constants, 3);
    2880:     *constants = ds->constants;
    2881:   }
    2882:   PetscFunctionReturn(PETSC_SUCCESS);
    2883: }

    2885: /*@C
    2886:   PetscDSSetConstants - Set the array of constants passed to point functions

    2888:   Not Collective

    2890:   Input Parameters:
    2891: + ds           - The `PetscDS` object
    2892: . numConstants - The number of constants
    2893: - constants    - The array of constants, `NULL` if there are none

    2895:   Level: intermediate

    2897: .seealso: `PetscDS`, `PetscDSGetConstants()`, `PetscDSCreate()`
    2898: @*/
    2899: PetscErrorCode PetscDSSetConstants(PetscDS ds, PetscInt numConstants, PetscScalar constants[])
    2900: {
    2901:   PetscFunctionBegin;
    2903:   if (numConstants != ds->numConstants) {
    2904:     PetscCall(PetscFree(ds->constants));
    2905:     ds->numConstants = numConstants;
    2906:     PetscCall(PetscMalloc1(ds->numConstants + ds->numFuncConstants, &ds->constants));
    2907:   }
    2908:   if (ds->numConstants) {
    2909:     PetscAssertPointer(constants, 3);
    2910:     PetscCall(PetscArraycpy(ds->constants, constants, ds->numConstants));
    2911:   }
    2912:   PetscFunctionReturn(PETSC_SUCCESS);
    2913: }

    2915: /*@C
    2916:   PetscDSSetIntegrationParameters - Set the parameters for a particular integration

    2918:   Not Collective

    2920:   Input Parameters:
    2921: + ds     - The `PetscDS` object
    2922: . fieldI - The test field for a given point function, or PETSC_DETERMINE
    2923: - fieldJ - The basis field for a given point function, or PETSC_DETERMINE

    2925:   Level: intermediate

    2927: .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSGetConstants()`, `PetscDSCreate()`
    2928: @*/
    2929: PetscErrorCode PetscDSSetIntegrationParameters(PetscDS ds, PetscInt fieldI, PetscInt fieldJ)
    2930: {
    2931:   PetscFunctionBegin;
    2933:   ds->constants[ds->numConstants]     = fieldI;
    2934:   ds->constants[ds->numConstants + 1] = fieldJ;
    2935:   PetscFunctionReturn(PETSC_SUCCESS);
    2936: }

    2938: /*@C
    2939:   PetscDSSetCellParameters - Set the parameters for a particular cell

    2941:   Not Collective

    2943:   Input Parameters:
    2944: + ds     - The `PetscDS` object
    2945: - volume - The cell volume

    2947:   Level: intermediate

    2949: .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSGetConstants()`, `PetscDSCreate()`
    2950: @*/
    2951: PetscErrorCode PetscDSSetCellParameters(PetscDS ds, PetscReal volume)
    2952: {
    2953:   PetscFunctionBegin;
    2955:   ds->constants[ds->numConstants + 2] = volume;
    2956:   PetscFunctionReturn(PETSC_SUCCESS);
    2957: }

    2959: /*@
    2960:   PetscDSGetFieldIndex - Returns the index of the given field

    2962:   Not Collective

    2964:   Input Parameters:
    2965: + prob - The `PetscDS` object
    2966: - disc - The discretization object

    2968:   Output Parameter:
    2969: . f - The field number

    2971:   Level: beginner

    2973: .seealso: `PetscDS`, `PetscGetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2974: @*/
    2975: PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
    2976: {
    2977:   PetscInt g;

    2979:   PetscFunctionBegin;
    2981:   PetscAssertPointer(f, 3);
    2982:   *f = -1;
    2983:   for (g = 0; g < prob->Nf; ++g) {
    2984:     if (disc == prob->disc[g]) break;
    2985:   }
    2986:   PetscCheck(g != prob->Nf, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
    2987:   *f = g;
    2988:   PetscFunctionReturn(PETSC_SUCCESS);
    2989: }

    2991: /*@
    2992:   PetscDSGetFieldSize - Returns the size of the given field in the full space basis

    2994:   Not Collective

    2996:   Input Parameters:
    2997: + prob - The `PetscDS` object
    2998: - f    - The field number

    3000:   Output Parameter:
    3001: . size - The size

    3003:   Level: beginner

    3005: .seealso: `PetscDS`, `PetscDSGetFieldOffset()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3006: @*/
    3007: PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
    3008: {
    3009:   PetscFunctionBegin;
    3011:   PetscAssertPointer(size, 3);
    3012:   PetscCheck(!(f < 0) && !(f >= prob->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, prob->Nf);
    3013:   PetscCall(PetscDSSetUp(prob));
    3014:   *size = prob->Nb[f];
    3015:   PetscFunctionReturn(PETSC_SUCCESS);
    3016: }

    3018: /*@
    3019:   PetscDSGetFieldOffset - Returns the offset of the given field in the full space basis

    3021:   Not Collective

    3023:   Input Parameters:
    3024: + prob - The `PetscDS` object
    3025: - f    - The field number

    3027:   Output Parameter:
    3028: . off - The offset

    3030:   Level: beginner

    3032: .seealso: `PetscDS`, `PetscDSGetFieldSize()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3033: @*/
    3034: PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
    3035: {
    3036:   PetscInt size, g;

    3038:   PetscFunctionBegin;
    3040:   PetscAssertPointer(off, 3);
    3041:   PetscCheck(!(f < 0) && !(f >= prob->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, prob->Nf);
    3042:   *off = 0;
    3043:   for (g = 0; g < f; ++g) {
    3044:     PetscCall(PetscDSGetFieldSize(prob, g, &size));
    3045:     *off += size;
    3046:   }
    3047:   PetscFunctionReturn(PETSC_SUCCESS);
    3048: }

    3050: /*@
    3051:   PetscDSGetFieldOffsetCohesive - Returns the offset of the given field in the full space basis on a cohesive cell

    3053:   Not Collective

    3055:   Input Parameters:
    3056: + ds - The `PetscDS` object
    3057: - f  - The field number

    3059:   Output Parameter:
    3060: . off - The offset

    3062:   Level: beginner

    3064: .seealso: `PetscDS`, `PetscDSGetFieldSize()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3065: @*/
    3066: PetscErrorCode PetscDSGetFieldOffsetCohesive(PetscDS ds, PetscInt f, PetscInt *off)
    3067: {
    3068:   PetscInt size, g;

    3070:   PetscFunctionBegin;
    3072:   PetscAssertPointer(off, 3);
    3073:   PetscCheck(!(f < 0) && !(f >= ds->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, ds->Nf);
    3074:   *off = 0;
    3075:   for (g = 0; g < f; ++g) {
    3076:     PetscBool cohesive;

    3078:     PetscCall(PetscDSGetCohesive(ds, g, &cohesive));
    3079:     PetscCall(PetscDSGetFieldSize(ds, g, &size));
    3080:     *off += cohesive ? size : size * 2;
    3081:   }
    3082:   PetscFunctionReturn(PETSC_SUCCESS);
    3083: }

    3085: /*@
    3086:   PetscDSGetDimensions - Returns the size of the approximation space for each field on an evaluation point

    3088:   Not Collective

    3090:   Input Parameter:
    3091: . prob - The `PetscDS` object

    3093:   Output Parameter:
    3094: . dimensions - The number of dimensions

    3096:   Level: beginner

    3098: .seealso: `PetscDS`, `PetscDSGetComponentOffsets()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3099: @*/
    3100: PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
    3101: {
    3102:   PetscFunctionBegin;
    3104:   PetscCall(PetscDSSetUp(prob));
    3105:   PetscAssertPointer(dimensions, 2);
    3106:   *dimensions = prob->Nb;
    3107:   PetscFunctionReturn(PETSC_SUCCESS);
    3108: }

    3110: /*@
    3111:   PetscDSGetComponents - Returns the number of components for each field on an evaluation point

    3113:   Not Collective

    3115:   Input Parameter:
    3116: . prob - The `PetscDS` object

    3118:   Output Parameter:
    3119: . components - The number of components

    3121:   Level: beginner

    3123: .seealso: `PetscDS`, `PetscDSGetComponentOffsets()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3124: @*/
    3125: PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
    3126: {
    3127:   PetscFunctionBegin;
    3129:   PetscCall(PetscDSSetUp(prob));
    3130:   PetscAssertPointer(components, 2);
    3131:   *components = prob->Nc;
    3132:   PetscFunctionReturn(PETSC_SUCCESS);
    3133: }

    3135: /*@
    3136:   PetscDSGetComponentOffset - Returns the offset of the given field on an evaluation point

    3138:   Not Collective

    3140:   Input Parameters:
    3141: + prob - The `PetscDS` object
    3142: - f    - The field number

    3144:   Output Parameter:
    3145: . off - The offset

    3147:   Level: beginner

    3149: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3150: @*/
    3151: PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
    3152: {
    3153:   PetscFunctionBegin;
    3155:   PetscAssertPointer(off, 3);
    3156:   PetscCheck(!(f < 0) && !(f >= prob->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, prob->Nf);
    3157:   PetscCall(PetscDSSetUp(prob));
    3158:   *off = prob->off[f];
    3159:   PetscFunctionReturn(PETSC_SUCCESS);
    3160: }

    3162: /*@
    3163:   PetscDSGetComponentOffsets - Returns the offset of each field on an evaluation point

    3165:   Not Collective

    3167:   Input Parameter:
    3168: . prob - The `PetscDS` object

    3170:   Output Parameter:
    3171: . offsets - The offsets

    3173:   Level: beginner

    3175: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3176: @*/
    3177: PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
    3178: {
    3179:   PetscFunctionBegin;
    3181:   PetscAssertPointer(offsets, 2);
    3182:   PetscCall(PetscDSSetUp(prob));
    3183:   *offsets = prob->off;
    3184:   PetscFunctionReturn(PETSC_SUCCESS);
    3185: }

    3187: /*@
    3188:   PetscDSGetComponentDerivativeOffsets - Returns the offset of each field derivative on an evaluation point

    3190:   Not Collective

    3192:   Input Parameter:
    3193: . prob - The `PetscDS` object

    3195:   Output Parameter:
    3196: . offsets - The offsets

    3198:   Level: beginner

    3200: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3201: @*/
    3202: PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
    3203: {
    3204:   PetscFunctionBegin;
    3206:   PetscAssertPointer(offsets, 2);
    3207:   PetscCall(PetscDSSetUp(prob));
    3208:   *offsets = prob->offDer;
    3209:   PetscFunctionReturn(PETSC_SUCCESS);
    3210: }

    3212: /*@
    3213:   PetscDSGetComponentOffsetsCohesive - Returns the offset of each field on an evaluation point

    3215:   Not Collective

    3217:   Input Parameters:
    3218: + ds - The `PetscDS` object
    3219: - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive

    3221:   Output Parameter:
    3222: . offsets - The offsets

    3224:   Level: beginner

    3226: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3227: @*/
    3228: PetscErrorCode PetscDSGetComponentOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
    3229: {
    3230:   PetscFunctionBegin;
    3232:   PetscAssertPointer(offsets, 3);
    3233:   PetscCheck(ds->isCohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
    3234:   PetscCheck(!(s < 0) && !(s > 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %" PetscInt_FMT " is not in [0, 2]", s);
    3235:   PetscCall(PetscDSSetUp(ds));
    3236:   *offsets = ds->offCohesive[s];
    3237:   PetscFunctionReturn(PETSC_SUCCESS);
    3238: }

    3240: /*@
    3241:   PetscDSGetComponentDerivativeOffsetsCohesive - Returns the offset of each field derivative on an evaluation point

    3243:   Not Collective

    3245:   Input Parameters:
    3246: + ds - The `PetscDS` object
    3247: - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive

    3249:   Output Parameter:
    3250: . offsets - The offsets

    3252:   Level: beginner

    3254: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    3255: @*/
    3256: PetscErrorCode PetscDSGetComponentDerivativeOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
    3257: {
    3258:   PetscFunctionBegin;
    3260:   PetscAssertPointer(offsets, 3);
    3261:   PetscCheck(ds->isCohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
    3262:   PetscCheck(!(s < 0) && !(s > 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %" PetscInt_FMT " is not in [0, 2]", s);
    3263:   PetscCall(PetscDSSetUp(ds));
    3264:   *offsets = ds->offDerCohesive[s];
    3265:   PetscFunctionReturn(PETSC_SUCCESS);
    3266: }

    3268: /*@C
    3269:   PetscDSGetTabulation - Return the basis tabulation at quadrature points for the volume discretization

    3271:   Not Collective

    3273:   Input Parameter:
    3274: . prob - The `PetscDS` object

    3276:   Output Parameter:
    3277: . T - The basis function and derivatives tabulation at quadrature points for each field

    3279:   Level: intermediate

    3281: .seealso: `PetscDS`, `PetscTabulation`, `PetscDSCreate()`
    3282: @*/
    3283: PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[])
    3284: {
    3285:   PetscFunctionBegin;
    3287:   PetscAssertPointer(T, 2);
    3288:   PetscCall(PetscDSSetUp(prob));
    3289:   *T = prob->T;
    3290:   PetscFunctionReturn(PETSC_SUCCESS);
    3291: }

    3293: /*@C
    3294:   PetscDSGetFaceTabulation - Return the basis tabulation at quadrature points on the faces

    3296:   Not Collective

    3298:   Input Parameter:
    3299: . prob - The `PetscDS` object

    3301:   Output Parameter:
    3302: . Tf - The basis function and derivative tabulation on each local face at quadrature points for each and field

    3304:   Level: intermediate

    3306: .seealso: `PetscTabulation`, `PetscDS`, `PetscDSGetTabulation()`, `PetscDSCreate()`
    3307: @*/
    3308: PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
    3309: {
    3310:   PetscFunctionBegin;
    3312:   PetscAssertPointer(Tf, 2);
    3313:   PetscCall(PetscDSSetUp(prob));
    3314:   *Tf = prob->Tf;
    3315:   PetscFunctionReturn(PETSC_SUCCESS);
    3316: }

    3318: PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
    3319: {
    3320:   PetscFunctionBegin;
    3322:   PetscCall(PetscDSSetUp(prob));
    3323:   if (u) {
    3324:     PetscAssertPointer(u, 2);
    3325:     *u = prob->u;
    3326:   }
    3327:   if (u_t) {
    3328:     PetscAssertPointer(u_t, 3);
    3329:     *u_t = prob->u_t;
    3330:   }
    3331:   if (u_x) {
    3332:     PetscAssertPointer(u_x, 4);
    3333:     *u_x = prob->u_x;
    3334:   }
    3335:   PetscFunctionReturn(PETSC_SUCCESS);
    3336: }

    3338: PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar **f0, PetscScalar **f1, PetscScalar **g0, PetscScalar **g1, PetscScalar **g2, PetscScalar **g3)
    3339: {
    3340:   PetscFunctionBegin;
    3342:   PetscCall(PetscDSSetUp(prob));
    3343:   if (f0) {
    3344:     PetscAssertPointer(f0, 2);
    3345:     *f0 = prob->f0;
    3346:   }
    3347:   if (f1) {
    3348:     PetscAssertPointer(f1, 3);
    3349:     *f1 = prob->f1;
    3350:   }
    3351:   if (g0) {
    3352:     PetscAssertPointer(g0, 4);
    3353:     *g0 = prob->g0;
    3354:   }
    3355:   if (g1) {
    3356:     PetscAssertPointer(g1, 5);
    3357:     *g1 = prob->g1;
    3358:   }
    3359:   if (g2) {
    3360:     PetscAssertPointer(g2, 6);
    3361:     *g2 = prob->g2;
    3362:   }
    3363:   if (g3) {
    3364:     PetscAssertPointer(g3, 7);
    3365:     *g3 = prob->g3;
    3366:   }
    3367:   PetscFunctionReturn(PETSC_SUCCESS);
    3368: }

    3370: PetscErrorCode PetscDSGetWorkspace(PetscDS prob, PetscReal **x, PetscScalar **basisReal, PetscScalar **basisDerReal, PetscScalar **testReal, PetscScalar **testDerReal)
    3371: {
    3372:   PetscFunctionBegin;
    3374:   PetscCall(PetscDSSetUp(prob));
    3375:   if (x) {
    3376:     PetscAssertPointer(x, 2);
    3377:     *x = prob->x;
    3378:   }
    3379:   if (basisReal) {
    3380:     PetscAssertPointer(basisReal, 3);
    3381:     *basisReal = prob->basisReal;
    3382:   }
    3383:   if (basisDerReal) {
    3384:     PetscAssertPointer(basisDerReal, 4);
    3385:     *basisDerReal = prob->basisDerReal;
    3386:   }
    3387:   if (testReal) {
    3388:     PetscAssertPointer(testReal, 5);
    3389:     *testReal = prob->testReal;
    3390:   }
    3391:   if (testDerReal) {
    3392:     PetscAssertPointer(testDerReal, 6);
    3393:     *testDerReal = prob->testDerReal;
    3394:   }
    3395:   PetscFunctionReturn(PETSC_SUCCESS);
    3396: }

    3398: /*@C
    3399:   PetscDSAddBoundary - Add a boundary condition to the model.

    3401:   Collective

    3403:   Input Parameters:
    3404: + ds       - The PetscDS object
    3405: . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
    3406: . name     - The BC name
    3407: . label    - The label defining constrained points
    3408: . Nv       - The number of `DMLabel` values for constrained points
    3409: . values   - An array of label values for constrained points
    3410: . field    - The field to constrain
    3411: . Nc       - The number of constrained field components (0 will constrain all fields)
    3412: . comps    - An array of constrained component numbers
    3413: . bcFunc   - A pointwise function giving boundary values
    3414: . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
    3415: - ctx      - An optional user context for bcFunc

    3417:   Output Parameter:
    3418: . bd - The boundary number

    3420:   Options Database Keys:
    3421: + -bc_<boundary name> <num>      - Overrides the boundary ids
    3422: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    3424:   Level: developer

    3426:   Note:
    3427:   Both `bcFunc` and `bcFunc_t` will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:

    3429: $ void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])

    3431:   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
    3432: .vb
    3433:   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    3434:               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    3435:               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    3436:               PetscReal time, const PetscReal x[], PetscScalar bcval[])
    3437: .ve
    3438: + dim - the spatial dimension
    3439: . Nf - the number of fields
    3440: . uOff - the offset into u[] and u_t[] for each field
    3441: . uOff_x - the offset into u_x[] for each field
    3442: . u - each field evaluated at the current point
    3443: . u_t - the time derivative of each field evaluated at the current point
    3444: . u_x - the gradient of each field evaluated at the current point
    3445: . aOff - the offset into a[] and a_t[] for each auxiliary field
    3446: . aOff_x - the offset into a_x[] for each auxiliary field
    3447: . a - each auxiliary field evaluated at the current point
    3448: . a_t - the time derivative of each auxiliary field evaluated at the current point
    3449: . a_x - the gradient of auxiliary each field evaluated at the current point
    3450: . t - current time
    3451: . x - coordinates of the current point
    3452: . numConstants - number of constant parameters
    3453: . constants - constant parameters
    3454: - bcval - output values at the current point

    3456:   Notes:
    3457:   The pointwise functions are used to provide boundary values for essential boundary
    3458:   conditions. In FEM, they are acting upon by dual basis functionals to generate FEM
    3459:   coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary
    3460:   integrals should be performed, using the kernels from `PetscDSSetBdResidual()`.

    3462: .seealso: `PetscDS`, `PetscWeakForm`, `DMLabel`, `DMBoundaryConditionType`, `PetscDSAddBoundaryByName()`, `PetscDSGetBoundary()`, `PetscDSSetResidual()`, `PetscDSSetBdResidual()`
    3463: @*/
    3464: PetscErrorCode PetscDSAddBoundary(PetscDS ds, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
    3465: {
    3466:   DSBoundary  head = ds->boundary, b;
    3467:   PetscInt    n    = 0;
    3468:   const char *lname;

    3470:   PetscFunctionBegin;
    3473:   PetscAssertPointer(name, 3);
    3478:   PetscCheck(field >= 0 && field < ds->Nf, PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, ds->Nf);
    3479:   if (Nc > 0) {
    3480:     PetscInt *fcomps;
    3481:     PetscInt  c;

    3483:     PetscCall(PetscDSGetComponents(ds, &fcomps));
    3484:     PetscCheck(Nc <= fcomps[field], PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_OUTOFRANGE, "Number of constrained components %" PetscInt_FMT " > %" PetscInt_FMT " components for field %" PetscInt_FMT, Nc, fcomps[field], field);
    3485:     for (c = 0; c < Nc; ++c) {
    3486:       PetscCheck(comps[c] >= 0 && comps[c] < fcomps[field], PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_OUTOFRANGE, "Constrained component[%" PetscInt_FMT "] %" PetscInt_FMT " not in [0, %" PetscInt_FMT ") components for field %" PetscInt_FMT, c, comps[c], fcomps[field], field);
    3487:     }
    3488:   }
    3489:   PetscCall(PetscNew(&b));
    3490:   PetscCall(PetscStrallocpy(name, (char **)&b->name));
    3491:   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
    3492:   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
    3493:   PetscCall(PetscMalloc1(Nv, &b->values));
    3494:   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
    3495:   PetscCall(PetscMalloc1(Nc, &b->comps));
    3496:   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
    3497:   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
    3498:   PetscCall(PetscStrallocpy(lname, (char **)&b->lname));
    3499:   b->type   = type;
    3500:   b->label  = label;
    3501:   b->Nv     = Nv;
    3502:   b->field  = field;
    3503:   b->Nc     = Nc;
    3504:   b->func   = bcFunc;
    3505:   b->func_t = bcFunc_t;
    3506:   b->ctx    = ctx;
    3507:   b->next   = NULL;
    3508:   /* Append to linked list so that we can preserve the order */
    3509:   if (!head) ds->boundary = b;
    3510:   while (head) {
    3511:     if (!head->next) {
    3512:       head->next = b;
    3513:       head       = b;
    3514:     }
    3515:     head = head->next;
    3516:     ++n;
    3517:   }
    3518:   if (bd) {
    3519:     PetscAssertPointer(bd, 13);
    3520:     *bd = n;
    3521:   }
    3522:   PetscFunctionReturn(PETSC_SUCCESS);
    3523: }

    3525: // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
    3526: /*@C
    3527:   PetscDSAddBoundaryByName - Add a boundary condition to the model.

    3529:   Collective

    3531:   Input Parameters:
    3532: + ds       - The `PetscDS` object
    3533: . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
    3534: . name     - The BC name
    3535: . lname    - The naem of the label defining constrained points
    3536: . Nv       - The number of `DMLabel` values for constrained points
    3537: . values   - An array of label values for constrained points
    3538: . field    - The field to constrain
    3539: . Nc       - The number of constrained field components (0 will constrain all fields)
    3540: . comps    - An array of constrained component numbers
    3541: . bcFunc   - A pointwise function giving boundary values
    3542: . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
    3543: - ctx      - An optional user context for bcFunc

    3545:   Output Parameter:
    3546: . bd - The boundary number

    3548:   Options Database Keys:
    3549: + -bc_<boundary name> <num>      - Overrides the boundary ids
    3550: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    3552:   Calling Sequence of `bcFunc` and `bcFunc_t`:
    3553:   If the type is `DM_BC_ESSENTIAL`
    3554: .vb
    3555:   void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
    3556: .ve
    3557:   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value,
    3558: .vb
    3559:   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    3560:               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    3561:               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    3562:               PetscReal time, const PetscReal x[], PetscScalar bcval[])
    3563: .ve
    3564: + dim - the spatial dimension
    3565: . Nf - the number of fields
    3566: . uOff - the offset into u[] and u_t[] for each field
    3567: . uOff_x - the offset into u_x[] for each field
    3568: . u - each field evaluated at the current point
    3569: . u_t - the time derivative of each field evaluated at the current point
    3570: . u_x - the gradient of each field evaluated at the current point
    3571: . aOff - the offset into a[] and a_t[] for each auxiliary field
    3572: . aOff_x - the offset into a_x[] for each auxiliary field
    3573: . a - each auxiliary field evaluated at the current point
    3574: . a_t - the time derivative of each auxiliary field evaluated at the current point
    3575: . a_x - the gradient of auxiliary each field evaluated at the current point
    3576: . t - current time
    3577: . x - coordinates of the current point
    3578: . numConstants - number of constant parameters
    3579: . constants - constant parameters
    3580: - bcval - output values at the current point

    3582:   Level: developer

    3584:   Notes:
    3585:   The pointwise functions are used to provide boundary values for essential boundary
    3586:   conditions. In FEM, they are acting upon by dual basis functionals to generate FEM
    3587:   coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary
    3588:   integrals should be performed, using the kernels from `PetscDSSetBdResidual()`.

    3590:   This function should only be used with `DMFOREST` currently, since labels cannot be defined before the underlying `DMPLEX` is built.

    3592: .seealso: `PetscDS`, `PetscWeakForm`, `DMLabel`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`, `PetscDSSetResidual()`, `PetscDSSetBdResidual()`
    3593: @*/
    3594: PetscErrorCode PetscDSAddBoundaryByName(PetscDS ds, DMBoundaryConditionType type, const char name[], const char lname[], PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
    3595: {
    3596:   DSBoundary head = ds->boundary, b;
    3597:   PetscInt   n    = 0;

    3599:   PetscFunctionBegin;
    3602:   PetscAssertPointer(name, 3);
    3603:   PetscAssertPointer(lname, 4);
    3607:   PetscCall(PetscNew(&b));
    3608:   PetscCall(PetscStrallocpy(name, (char **)&b->name));
    3609:   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
    3610:   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
    3611:   PetscCall(PetscMalloc1(Nv, &b->values));
    3612:   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
    3613:   PetscCall(PetscMalloc1(Nc, &b->comps));
    3614:   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
    3615:   PetscCall(PetscStrallocpy(lname, (char **)&b->lname));
    3616:   b->type   = type;
    3617:   b->label  = NULL;
    3618:   b->Nv     = Nv;
    3619:   b->field  = field;
    3620:   b->Nc     = Nc;
    3621:   b->func   = bcFunc;
    3622:   b->func_t = bcFunc_t;
    3623:   b->ctx    = ctx;
    3624:   b->next   = NULL;
    3625:   /* Append to linked list so that we can preserve the order */
    3626:   if (!head) ds->boundary = b;
    3627:   while (head) {
    3628:     if (!head->next) {
    3629:       head->next = b;
    3630:       head       = b;
    3631:     }
    3632:     head = head->next;
    3633:     ++n;
    3634:   }
    3635:   if (bd) {
    3636:     PetscAssertPointer(bd, 13);
    3637:     *bd = n;
    3638:   }
    3639:   PetscFunctionReturn(PETSC_SUCCESS);
    3640: }

    3642: /*@C
    3643:   PetscDSUpdateBoundary - Change a boundary condition for the model.

    3645:   Input Parameters:
    3646: + ds       - The `PetscDS` object
    3647: . bd       - The boundary condition number
    3648: . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
    3649: . name     - The BC name
    3650: . label    - The label defining constrained points
    3651: . Nv       - The number of `DMLabel` ids for constrained points
    3652: . values   - An array of ids for constrained points
    3653: . field    - The field to constrain
    3654: . Nc       - The number of constrained field components
    3655: . comps    - An array of constrained component numbers
    3656: . bcFunc   - A pointwise function giving boundary values
    3657: . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
    3658: - ctx      - An optional user context for bcFunc

    3660:   Level: developer

    3662:   Notes:
    3663:   The pointwise functions are used to provide boundary values for essential boundary
    3664:   conditions. In FEM, they are acting upon by dual basis functionals to generate FEM
    3665:   coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary
    3666:   integrals should be performed, using the kernels from `PetscDSSetBdResidual()`.

    3668:   The boundary condition number is the order in which it was registered. The user can get the number of boundary conditions from `PetscDSGetNumBoundary()`.
    3669:   See `PetscDSAddBoundary()` for a description of the calling sequences for the callbacks.

    3671: .seealso: `PetscDS`, `PetscWeakForm`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`, `PetscDSGetNumBoundary()`, `DMLabel`
    3672: @*/
    3673: PetscErrorCode PetscDSUpdateBoundary(PetscDS ds, PetscInt bd, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx)
    3674: {
    3675:   DSBoundary b = ds->boundary;
    3676:   PetscInt   n = 0;

    3678:   PetscFunctionBegin;
    3680:   while (b) {
    3681:     if (n == bd) break;
    3682:     b = b->next;
    3683:     ++n;
    3684:   }
    3685:   PetscCheck(b, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bd, n);
    3686:   if (name) {
    3687:     PetscCall(PetscFree(b->name));
    3688:     PetscCall(PetscStrallocpy(name, (char **)&b->name));
    3689:   }
    3690:   b->type = type;
    3691:   if (label) {
    3692:     const char *name;

    3694:     b->label = label;
    3695:     PetscCall(PetscFree(b->lname));
    3696:     PetscCall(PetscObjectGetName((PetscObject)label, &name));
    3697:     PetscCall(PetscStrallocpy(name, (char **)&b->lname));
    3698:   }
    3699:   if (Nv >= 0) {
    3700:     b->Nv = Nv;
    3701:     PetscCall(PetscFree(b->values));
    3702:     PetscCall(PetscMalloc1(Nv, &b->values));
    3703:     if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
    3704:   }
    3705:   if (field >= 0) b->field = field;
    3706:   if (Nc >= 0) {
    3707:     b->Nc = Nc;
    3708:     PetscCall(PetscFree(b->comps));
    3709:     PetscCall(PetscMalloc1(Nc, &b->comps));
    3710:     if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
    3711:   }
    3712:   if (bcFunc) b->func = bcFunc;
    3713:   if (bcFunc_t) b->func_t = bcFunc_t;
    3714:   if (ctx) b->ctx = ctx;
    3715:   PetscFunctionReturn(PETSC_SUCCESS);
    3716: }

    3718: /*@
    3719:   PetscDSGetNumBoundary - Get the number of registered BC

    3721:   Input Parameter:
    3722: . ds - The `PetscDS` object

    3724:   Output Parameter:
    3725: . numBd - The number of BC

    3727:   Level: intermediate

    3729: .seealso: `PetscDS`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`
    3730: @*/
    3731: PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
    3732: {
    3733:   DSBoundary b = ds->boundary;

    3735:   PetscFunctionBegin;
    3737:   PetscAssertPointer(numBd, 2);
    3738:   *numBd = 0;
    3739:   while (b) {
    3740:     ++(*numBd);
    3741:     b = b->next;
    3742:   }
    3743:   PetscFunctionReturn(PETSC_SUCCESS);
    3744: }

    3746: /*@C
    3747:   PetscDSGetBoundary - Gets a boundary condition to the model

    3749:   Input Parameters:
    3750: + ds - The `PetscDS` object
    3751: - bd - The BC number

    3753:   Output Parameters:
    3754: + wf     - The `PetscWeakForm` holding the pointwise functions
    3755: . type   - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
    3756: . name   - The BC name
    3757: . label  - The label defining constrained points
    3758: . Nv     - The number of `DMLabel` ids for constrained points
    3759: . values - An array of ids for constrained points
    3760: . field  - The field to constrain
    3761: . Nc     - The number of constrained field components
    3762: . comps  - An array of constrained component numbers
    3763: . func   - A pointwise function giving boundary values
    3764: . func_t - A pointwise function giving the time derivative of the boundary values
    3765: - ctx    - An optional user context for bcFunc

    3767:   Options Database Keys:
    3768: + -bc_<boundary name> <num>      - Overrides the boundary ids
    3769: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    3771:   Level: developer

    3773: .seealso: `PetscDS`, `PetscWeakForm`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `DMLabel`
    3774: @*/
    3775: PetscErrorCode PetscDSGetBoundary(PetscDS ds, PetscInt bd, PetscWeakForm *wf, DMBoundaryConditionType *type, const char *name[], DMLabel *label, PetscInt *Nv, const PetscInt *values[], PetscInt *field, PetscInt *Nc, const PetscInt *comps[], void (**func)(void), void (**func_t)(void), void **ctx)
    3776: {
    3777:   DSBoundary b = ds->boundary;
    3778:   PetscInt   n = 0;

    3780:   PetscFunctionBegin;
    3782:   while (b) {
    3783:     if (n == bd) break;
    3784:     b = b->next;
    3785:     ++n;
    3786:   }
    3787:   PetscCheck(b, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bd, n);
    3788:   if (wf) {
    3789:     PetscAssertPointer(wf, 3);
    3790:     *wf = b->wf;
    3791:   }
    3792:   if (type) {
    3793:     PetscAssertPointer(type, 4);
    3794:     *type = b->type;
    3795:   }
    3796:   if (name) {
    3797:     PetscAssertPointer(name, 5);
    3798:     *name = b->name;
    3799:   }
    3800:   if (label) {
    3801:     PetscAssertPointer(label, 6);
    3802:     *label = b->label;
    3803:   }
    3804:   if (Nv) {
    3805:     PetscAssertPointer(Nv, 7);
    3806:     *Nv = b->Nv;
    3807:   }
    3808:   if (values) {
    3809:     PetscAssertPointer(values, 8);
    3810:     *values = b->values;
    3811:   }
    3812:   if (field) {
    3813:     PetscAssertPointer(field, 9);
    3814:     *field = b->field;
    3815:   }
    3816:   if (Nc) {
    3817:     PetscAssertPointer(Nc, 10);
    3818:     *Nc = b->Nc;
    3819:   }
    3820:   if (comps) {
    3821:     PetscAssertPointer(comps, 11);
    3822:     *comps = b->comps;
    3823:   }
    3824:   if (func) {
    3825:     PetscAssertPointer(func, 12);
    3826:     *func = b->func;
    3827:   }
    3828:   if (func_t) {
    3829:     PetscAssertPointer(func_t, 13);
    3830:     *func_t = b->func_t;
    3831:   }
    3832:   if (ctx) {
    3833:     PetscAssertPointer(ctx, 14);
    3834:     *ctx = b->ctx;
    3835:   }
    3836:   PetscFunctionReturn(PETSC_SUCCESS);
    3837: }

    3839: /*@
    3840:   PetscDSUpdateBoundaryLabels - Update `DMLabel` in each boundary condition using the label name and the input `DM`

    3842:   Not Collective

    3844:   Input Parameters:
    3845: + ds - The source `PetscDS` object
    3846: - dm - The `DM` holding labels

    3848:   Level: intermediate

    3850: .seealso: `PetscDS`, `DMBoundary`, `DM`, `PetscDSCopyBoundary()`, `PetscDSCreate()`, `DMGetLabel()`
    3851: @*/
    3852: PetscErrorCode PetscDSUpdateBoundaryLabels(PetscDS ds, DM dm)
    3853: {
    3854:   DSBoundary b;

    3856:   PetscFunctionBegin;
    3859:   for (b = ds->boundary; b; b = b->next) {
    3860:     if (b->lname) PetscCall(DMGetLabel(dm, b->lname, &b->label));
    3861:   }
    3862:   PetscFunctionReturn(PETSC_SUCCESS);
    3863: }

    3865: static PetscErrorCode DSBoundaryDuplicate_Internal(DSBoundary b, DSBoundary *bNew)
    3866: {
    3867:   PetscFunctionBegin;
    3868:   PetscCall(PetscNew(bNew));
    3869:   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &(*bNew)->wf));
    3870:   PetscCall(PetscWeakFormCopy(b->wf, (*bNew)->wf));
    3871:   PetscCall(PetscStrallocpy(b->name, (char **)&((*bNew)->name)));
    3872:   PetscCall(PetscStrallocpy(b->lname, (char **)&((*bNew)->lname)));
    3873:   (*bNew)->type  = b->type;
    3874:   (*bNew)->label = b->label;
    3875:   (*bNew)->Nv    = b->Nv;
    3876:   PetscCall(PetscMalloc1(b->Nv, &(*bNew)->values));
    3877:   PetscCall(PetscArraycpy((*bNew)->values, b->values, b->Nv));
    3878:   (*bNew)->field = b->field;
    3879:   (*bNew)->Nc    = b->Nc;
    3880:   PetscCall(PetscMalloc1(b->Nc, &(*bNew)->comps));
    3881:   PetscCall(PetscArraycpy((*bNew)->comps, b->comps, b->Nc));
    3882:   (*bNew)->func   = b->func;
    3883:   (*bNew)->func_t = b->func_t;
    3884:   (*bNew)->ctx    = b->ctx;
    3885:   PetscFunctionReturn(PETSC_SUCCESS);
    3886: }

    3888: /*@
    3889:   PetscDSCopyBoundary - Copy all boundary condition objects to the new problem

    3891:   Not Collective

    3893:   Input Parameters:
    3894: + ds        - The source `PetscDS` object
    3895: . numFields - The number of selected fields, or `PETSC_DEFAULT` for all fields
    3896: - fields    - The selected fields, or NULL for all fields

    3898:   Output Parameter:
    3899: . newds - The target `PetscDS`, now with a copy of the boundary conditions

    3901:   Level: intermediate

    3903: .seealso: `PetscDS`, `DMBoundary`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3904: @*/
    3905: PetscErrorCode PetscDSCopyBoundary(PetscDS ds, PetscInt numFields, const PetscInt fields[], PetscDS newds)
    3906: {
    3907:   DSBoundary b, *lastnext;

    3909:   PetscFunctionBegin;
    3912:   if (ds == newds) PetscFunctionReturn(PETSC_SUCCESS);
    3913:   PetscCall(PetscDSDestroyBoundary(newds));
    3914:   lastnext = &newds->boundary;
    3915:   for (b = ds->boundary; b; b = b->next) {
    3916:     DSBoundary bNew;
    3917:     PetscInt   fieldNew = -1;

    3919:     if (numFields > 0 && fields) {
    3920:       PetscInt f;

    3922:       for (f = 0; f < numFields; ++f)
    3923:         if (b->field == fields[f]) break;
    3924:       if (f == numFields) continue;
    3925:       fieldNew = f;
    3926:     }
    3927:     PetscCall(DSBoundaryDuplicate_Internal(b, &bNew));
    3928:     bNew->field = fieldNew < 0 ? b->field : fieldNew;
    3929:     *lastnext   = bNew;
    3930:     lastnext    = &bNew->next;
    3931:   }
    3932:   PetscFunctionReturn(PETSC_SUCCESS);
    3933: }

    3935: /*@
    3936:   PetscDSDestroyBoundary - Remove all `DMBoundary` objects from the `PetscDS`

    3938:   Not Collective

    3940:   Input Parameter:
    3941: . ds - The `PetscDS` object

    3943:   Level: intermediate

    3945: .seealso: `PetscDS`, `DMBoundary`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`
    3946: @*/
    3947: PetscErrorCode PetscDSDestroyBoundary(PetscDS ds)
    3948: {
    3949:   DSBoundary next = ds->boundary;

    3951:   PetscFunctionBegin;
    3952:   while (next) {
    3953:     DSBoundary b = next;

    3955:     next = b->next;
    3956:     PetscCall(PetscWeakFormDestroy(&b->wf));
    3957:     PetscCall(PetscFree(b->name));
    3958:     PetscCall(PetscFree(b->lname));
    3959:     PetscCall(PetscFree(b->values));
    3960:     PetscCall(PetscFree(b->comps));
    3961:     PetscCall(PetscFree(b));
    3962:   }
    3963:   PetscFunctionReturn(PETSC_SUCCESS);
    3964: }

    3966: /*@
    3967:   PetscDSSelectDiscretizations - Copy discretizations to the new problem with different field layout

    3969:   Not Collective

    3971:   Input Parameters:
    3972: + prob      - The `PetscDS` object
    3973: . numFields - Number of new fields
    3974: . fields    - Old field number for each new field
    3975: . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
    3976: - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit

    3978:   Output Parameter:
    3979: . newprob - The `PetscDS` copy

    3981:   Level: intermediate

    3983: .seealso: `PetscDS`, `PetscDSSelectEquations()`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3984: @*/
    3985: PetscErrorCode PetscDSSelectDiscretizations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscInt minDegree, PetscInt maxDegree, PetscDS newprob)
    3986: {
    3987:   PetscInt Nf, Nfn, fn;

    3989:   PetscFunctionBegin;
    3991:   if (fields) PetscAssertPointer(fields, 3);
    3993:   PetscCall(PetscDSGetNumFields(prob, &Nf));
    3994:   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
    3995:   numFields = numFields < 0 ? Nf : numFields;
    3996:   for (fn = 0; fn < numFields; ++fn) {
    3997:     const PetscInt f = fields ? fields[fn] : fn;
    3998:     PetscObject    disc;
    3999:     PetscClassId   id;

    4001:     if (f >= Nf) continue;
    4002:     PetscCall(PetscDSGetDiscretization(prob, f, &disc));
    4003:     PetscCallContinue(PetscObjectGetClassId(disc, &id));
    4004:     if (id == PETSCFE_CLASSID) {
    4005:       PetscFE fe;

    4007:       PetscCall(PetscFELimitDegree((PetscFE)disc, minDegree, maxDegree, &fe));
    4008:       PetscCall(PetscDSSetDiscretization(newprob, fn, (PetscObject)fe));
    4009:       PetscCall(PetscFEDestroy(&fe));
    4010:     } else {
    4011:       PetscCall(PetscDSSetDiscretization(newprob, fn, disc));
    4012:     }
    4013:   }
    4014:   PetscFunctionReturn(PETSC_SUCCESS);
    4015: }

    4017: /*@
    4018:   PetscDSSelectEquations - Copy pointwise function pointers to the new problem with different field layout

    4020:   Not Collective

    4022:   Input Parameters:
    4023: + prob      - The `PetscDS` object
    4024: . numFields - Number of new fields
    4025: - fields    - Old field number for each new field

    4027:   Output Parameter:
    4028: . newprob - The `PetscDS` copy

    4030:   Level: intermediate

    4032: .seealso: `PetscDS`, `PetscDSSelectDiscretizations()`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    4033: @*/
    4034: PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
    4035: {
    4036:   PetscInt Nf, Nfn, fn, gn;

    4038:   PetscFunctionBegin;
    4040:   if (fields) PetscAssertPointer(fields, 3);
    4042:   PetscCall(PetscDSGetNumFields(prob, &Nf));
    4043:   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
    4044:   PetscCheck(numFields <= Nfn, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_SIZ, "Number of fields %" PetscInt_FMT " to transfer must not be greater then the total number of fields %" PetscInt_FMT, numFields, Nfn);
    4045:   for (fn = 0; fn < numFields; ++fn) {
    4046:     const PetscInt   f = fields ? fields[fn] : fn;
    4047:     PetscPointFunc   obj;
    4048:     PetscPointFunc   f0, f1;
    4049:     PetscBdPointFunc f0Bd, f1Bd;
    4050:     PetscRiemannFunc r;

    4052:     if (f >= Nf) continue;
    4053:     PetscCall(PetscDSGetObjective(prob, f, &obj));
    4054:     PetscCall(PetscDSGetResidual(prob, f, &f0, &f1));
    4055:     PetscCall(PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd));
    4056:     PetscCall(PetscDSGetRiemannSolver(prob, f, &r));
    4057:     PetscCall(PetscDSSetObjective(newprob, fn, obj));
    4058:     PetscCall(PetscDSSetResidual(newprob, fn, f0, f1));
    4059:     PetscCall(PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd));
    4060:     PetscCall(PetscDSSetRiemannSolver(newprob, fn, r));
    4061:     for (gn = 0; gn < numFields; ++gn) {
    4062:       const PetscInt  g = fields ? fields[gn] : gn;
    4063:       PetscPointJac   g0, g1, g2, g3;
    4064:       PetscPointJac   g0p, g1p, g2p, g3p;
    4065:       PetscBdPointJac g0Bd, g1Bd, g2Bd, g3Bd;

    4067:       if (g >= Nf) continue;
    4068:       PetscCall(PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3));
    4069:       PetscCall(PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p));
    4070:       PetscCall(PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd));
    4071:       PetscCall(PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3));
    4072:       PetscCall(PetscDSSetJacobianPreconditioner(newprob, fn, gn, g0p, g1p, g2p, g3p));
    4073:       PetscCall(PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd));
    4074:     }
    4075:   }
    4076:   PetscFunctionReturn(PETSC_SUCCESS);
    4077: }

    4079: /*@
    4080:   PetscDSCopyEquations - Copy all pointwise function pointers to another `PetscDS`

    4082:   Not Collective

    4084:   Input Parameter:
    4085: . prob - The `PetscDS` object

    4087:   Output Parameter:
    4088: . newprob - The `PetscDS` copy

    4090:   Level: intermediate

    4092: .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    4093: @*/
    4094: PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
    4095: {
    4096:   PetscWeakForm wf, newwf;
    4097:   PetscInt      Nf, Ng;

    4099:   PetscFunctionBegin;
    4102:   PetscCall(PetscDSGetNumFields(prob, &Nf));
    4103:   PetscCall(PetscDSGetNumFields(newprob, &Ng));
    4104:   PetscCheck(Nf == Ng, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %" PetscInt_FMT " != %" PetscInt_FMT, Nf, Ng);
    4105:   PetscCall(PetscDSGetWeakForm(prob, &wf));
    4106:   PetscCall(PetscDSGetWeakForm(newprob, &newwf));
    4107:   PetscCall(PetscWeakFormCopy(wf, newwf));
    4108:   PetscFunctionReturn(PETSC_SUCCESS);
    4109: }

    4111: /*@
    4112:   PetscDSCopyConstants - Copy all constants to another `PetscDS`

    4114:   Not Collective

    4116:   Input Parameter:
    4117: . prob - The `PetscDS` object

    4119:   Output Parameter:
    4120: . newprob - The `PetscDS` copy

    4122:   Level: intermediate

    4124: .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    4125: @*/
    4126: PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
    4127: {
    4128:   PetscInt           Nc;
    4129:   const PetscScalar *constants;

    4131:   PetscFunctionBegin;
    4134:   PetscCall(PetscDSGetConstants(prob, &Nc, &constants));
    4135:   PetscCall(PetscDSSetConstants(newprob, Nc, (PetscScalar *)constants));
    4136:   PetscFunctionReturn(PETSC_SUCCESS);
    4137: }

    4139: /*@
    4140:   PetscDSCopyExactSolutions - Copy all exact solutions to another `PetscDS`

    4142:   Not Collective

    4144:   Input Parameter:
    4145: . ds - The `PetscDS` object

    4147:   Output Parameter:
    4148: . newds - The `PetscDS` copy

    4150:   Level: intermediate

    4152: .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    4153: @*/
    4154: PetscErrorCode PetscDSCopyExactSolutions(PetscDS ds, PetscDS newds)
    4155: {
    4156:   PetscSimplePointFn *sol;
    4157:   void               *ctx;
    4158:   PetscInt            Nf, f;

    4160:   PetscFunctionBegin;
    4163:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    4164:   for (f = 0; f < Nf; ++f) {
    4165:     PetscCall(PetscDSGetExactSolution(ds, f, &sol, &ctx));
    4166:     PetscCall(PetscDSSetExactSolution(newds, f, sol, ctx));
    4167:     PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, f, &sol, &ctx));
    4168:     PetscCall(PetscDSSetExactSolutionTimeDerivative(newds, f, sol, ctx));
    4169:   }
    4170:   PetscFunctionReturn(PETSC_SUCCESS);
    4171: }

    4173: PetscErrorCode PetscDSCopy(PetscDS ds, PetscInt minDegree, PetscInt maxDegree, DM dmNew, PetscDS dsNew)
    4174: {
    4175:   DSBoundary b;
    4176:   PetscInt   cdim, Nf, f, d;
    4177:   PetscBool  isCohesive;
    4178:   void      *ctx;

    4180:   PetscFunctionBegin;
    4181:   PetscCall(PetscDSCopyConstants(ds, dsNew));
    4182:   PetscCall(PetscDSCopyExactSolutions(ds, dsNew));
    4183:   PetscCall(PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, minDegree, maxDegree, dsNew));
    4184:   PetscCall(PetscDSCopyEquations(ds, dsNew));
    4185:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    4186:   for (f = 0; f < Nf; ++f) {
    4187:     PetscCall(PetscDSGetContext(ds, f, &ctx));
    4188:     PetscCall(PetscDSSetContext(dsNew, f, ctx));
    4189:     PetscCall(PetscDSGetCohesive(ds, f, &isCohesive));
    4190:     PetscCall(PetscDSSetCohesive(dsNew, f, isCohesive));
    4191:     PetscCall(PetscDSGetJetDegree(ds, f, &d));
    4192:     PetscCall(PetscDSSetJetDegree(dsNew, f, d));
    4193:   }
    4194:   if (Nf) {
    4195:     PetscCall(PetscDSGetCoordinateDimension(ds, &cdim));
    4196:     PetscCall(PetscDSSetCoordinateDimension(dsNew, cdim));
    4197:   }
    4198:   PetscCall(PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew));
    4199:   for (b = dsNew->boundary; b; b = b->next) {
    4200:     PetscCall(DMGetLabel(dmNew, b->lname, &b->label));
    4201:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
    4202:     //PetscCheck(b->label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
    4203:   }
    4204:   PetscFunctionReturn(PETSC_SUCCESS);
    4205: }

    4207: PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
    4208: {
    4209:   PetscInt dim, Nf, f;

    4211:   PetscFunctionBegin;
    4213:   PetscAssertPointer(subprob, 3);
    4214:   if (height == 0) {
    4215:     *subprob = prob;
    4216:     PetscFunctionReturn(PETSC_SUCCESS);
    4217:   }
    4218:   PetscCall(PetscDSGetNumFields(prob, &Nf));
    4219:   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
    4220:   PetscCheck(height <= dim, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %" PetscInt_FMT "], not %" PetscInt_FMT, dim, height);
    4221:   if (!prob->subprobs) PetscCall(PetscCalloc1(dim, &prob->subprobs));
    4222:   if (!prob->subprobs[height - 1]) {
    4223:     PetscInt cdim;

    4225:     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)prob), &prob->subprobs[height - 1]));
    4226:     PetscCall(PetscDSGetCoordinateDimension(prob, &cdim));
    4227:     PetscCall(PetscDSSetCoordinateDimension(prob->subprobs[height - 1], cdim));
    4228:     for (f = 0; f < Nf; ++f) {
    4229:       PetscFE      subfe;
    4230:       PetscObject  obj;
    4231:       PetscClassId id;

    4233:       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
    4234:       PetscCall(PetscObjectGetClassId(obj, &id));
    4235:       if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetHeightSubspace((PetscFE)obj, height, &subfe));
    4236:       else SETERRQ(PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %" PetscInt_FMT, f);
    4237:       PetscCall(PetscDSSetDiscretization(prob->subprobs[height - 1], f, (PetscObject)subfe));
    4238:     }
    4239:   }
    4240:   *subprob = prob->subprobs[height - 1];
    4241:   PetscFunctionReturn(PETSC_SUCCESS);
    4242: }

    4244: PetscErrorCode PetscDSPermuteQuadPoint(PetscDS ds, PetscInt ornt, PetscInt field, PetscInt q, PetscInt *qperm)
    4245: {
    4246:   IS              permIS;
    4247:   PetscQuadrature quad;
    4248:   DMPolytopeType  ct;
    4249:   const PetscInt *perm;
    4250:   PetscInt        Na, Nq;

    4252:   PetscFunctionBeginHot;
    4253:   PetscCall(PetscFEGetQuadrature((PetscFE)ds->disc[field], &quad));
    4254:   PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
    4255:   PetscCall(PetscQuadratureGetCellType(quad, &ct));
    4256:   PetscCheck(q >= 0 && q < Nq, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Quadrature point %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", q, Nq);
    4257:   Na = DMPolytopeTypeGetNumArrangements(ct) / 2;
    4258:   PetscCheck(ornt >= -Na && ornt < Na, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Orientation %" PetscInt_FMT " of %s is not in [%" PetscInt_FMT ", %" PetscInt_FMT ")", ornt, DMPolytopeTypes[ct], -Na, Na);
    4259:   if (!ds->quadPerm[(PetscInt)ct]) PetscCall(PetscQuadratureComputePermutations(quad, NULL, &ds->quadPerm[(PetscInt)ct]));
    4260:   permIS = ds->quadPerm[(PetscInt)ct][ornt + Na];
    4261:   PetscCall(ISGetIndices(permIS, &perm));
    4262:   *qperm = perm[q];
    4263:   PetscCall(ISRestoreIndices(permIS, &perm));
    4264:   PetscFunctionReturn(PETSC_SUCCESS);
    4265: }

    4267: PetscErrorCode PetscDSGetDiscType_Internal(PetscDS ds, PetscInt f, PetscDiscType *disctype)
    4268: {
    4269:   PetscObject  obj;
    4270:   PetscClassId id;
    4271:   PetscInt     Nf;

    4273:   PetscFunctionBegin;
    4275:   PetscAssertPointer(disctype, 3);
    4276:   *disctype = PETSC_DISC_NONE;
    4277:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    4278:   PetscCheck(f < Nf, PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_SIZ, "Field %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
    4279:   PetscCall(PetscDSGetDiscretization(ds, f, &obj));
    4280:   if (obj) {
    4281:     PetscCall(PetscObjectGetClassId(obj, &id));
    4282:     if (id == PETSCFE_CLASSID) *disctype = PETSC_DISC_FE;
    4283:     else *disctype = PETSC_DISC_FV;
    4284:   }
    4285:   PetscFunctionReturn(PETSC_SUCCESS);
    4286: }

    4288: static PetscErrorCode PetscDSDestroy_Basic(PetscDS ds)
    4289: {
    4290:   PetscFunctionBegin;
    4291:   PetscCall(PetscFree(ds->data));
    4292:   PetscFunctionReturn(PETSC_SUCCESS);
    4293: }

    4295: static PetscErrorCode PetscDSInitialize_Basic(PetscDS ds)
    4296: {
    4297:   PetscFunctionBegin;
    4298:   ds->ops->setfromoptions = NULL;
    4299:   ds->ops->setup          = NULL;
    4300:   ds->ops->view           = NULL;
    4301:   ds->ops->destroy        = PetscDSDestroy_Basic;
    4302:   PetscFunctionReturn(PETSC_SUCCESS);
    4303: }

    4305: /*MC
    4306:   PETSCDSBASIC = "basic" - A discrete system with pointwise residual and boundary residual functions

    4308:   Level: intermediate

    4310: .seealso: `PetscDSType`, `PetscDSCreate()`, `PetscDSSetType()`
    4311: M*/

    4313: PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS ds)
    4314: {
    4315:   PetscDS_Basic *b;

    4317:   PetscFunctionBegin;
    4319:   PetscCall(PetscNew(&b));
    4320:   ds->data = b;

    4322:   PetscCall(PetscDSInitialize_Basic(ds));
    4323:   PetscFunctionReturn(PETSC_SUCCESS);
    4324: }