Date: 2026-05-01T06:11:44+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: /*@C
      9:   PetscDSRegister - Adds a new `PetscDS` implementation

     11:   Not Collective; No Fortran Support

     13:   Input Parameters:
     14: + sname    - The name of a new user-defined creation routine
     15: - function - The creation routine itself

     17:   Example Usage:
     18: .vb
     19:     PetscDSRegister("my_ds", MyPetscDSCreate);
     20: .ve

     22:   Then, your PetscDS type can be chosen with the procedural interface via
     23: .vb
     24:     PetscDSCreate(MPI_Comm, PetscDS *);
     25:     PetscDSSetType(PetscDS, "my_ds");
     26: .ve
     27:   or at runtime via the option
     28: .vb
     29:     -petscds_type my_ds
     30: .ve

     32:   Level: advanced

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

     37: .seealso: `PetscDSType`, `PetscDS`, `PetscDSRegisterAll()`, `PetscDSRegisterDestroy()`
     38: @*/
     39: PetscErrorCode PetscDSRegister(const char sname[], PetscErrorCode (*function)(PetscDS))
     40: {
     41:   PetscFunctionBegin;
     42:   PetscCall(PetscFunctionListAdd(&PetscDSList, sname, function));
     43:   PetscFunctionReturn(PETSC_SUCCESS);
     44: }

     46: /*@
     47:   PetscDSSetType - Builds a particular `PetscDS`

     49:   Collective; No Fortran Support

     51:   Input Parameters:
     52: + prob - The `PetscDS` object
     53: - name - The `PetscDSType`

     55:   Options Database Key:
     56: . -petscds_type type - Sets the PetscDS type; use -help for a list of available types

     58:   Level: intermediate

     60: .seealso: `PetscDSType`, `PetscDS`, `PetscDSGetType()`, `PetscDSCreate()`
     61: @*/
     62: PetscErrorCode PetscDSSetType(PetscDS prob, PetscDSType name)
     63: {
     64:   PetscErrorCode (*r)(PetscDS);
     65:   PetscBool match;

     67:   PetscFunctionBegin;
     69:   PetscCall(PetscObjectTypeCompare((PetscObject)prob, name, &match));
     70:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

     72:   PetscCall(PetscDSRegisterAll());
     73:   PetscCall(PetscFunctionListFind(PetscDSList, name, &r));
     74:   PetscCheck(r, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDS type: %s", name);

     76:   PetscTryTypeMethod(prob, destroy);
     77:   prob->ops->destroy = NULL;

     79:   PetscCall((*r)(prob));
     80:   PetscCall(PetscObjectChangeTypeName((PetscObject)prob, name));
     81:   PetscFunctionReturn(PETSC_SUCCESS);
     82: }

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

     87:   Not Collective; No Fortran Support

     89:   Input Parameter:
     90: . prob - The `PetscDS`

     92:   Output Parameter:
     93: . name - The `PetscDSType` name

     95:   Level: intermediate

     97: .seealso: `PetscDSType`, `PetscDS`, `PetscDSSetType()`, `PetscDSCreate()`
     98: @*/
     99: PetscErrorCode PetscDSGetType(PetscDS prob, PetscDSType *name)
    100: {
    101:   PetscFunctionBegin;
    103:   PetscAssertPointer(name, 2);
    104:   PetscCall(PetscDSRegisterAll());
    105:   *name = ((PetscObject)prob)->type_name;
    106:   PetscFunctionReturn(PETSC_SUCCESS);
    107: }

    109: static PetscErrorCode PetscDSView_Ascii(PetscDS ds, PetscViewer viewer)
    110: {
    111:   PetscViewerFormat  format;
    112:   const PetscScalar *constants;
    113:   PetscInt           Nf, numConstants, f;

    115:   PetscFunctionBegin;
    116:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    117:   PetscCall(PetscViewerGetFormat(viewer, &format));
    118:   PetscCall(PetscViewerASCIIPrintf(viewer, "Discrete System with %" PetscInt_FMT " fields\n", Nf));
    119:   PetscCall(PetscViewerASCIIPushTab(viewer));
    120:   PetscCall(PetscViewerASCIIPrintf(viewer, "  cell total dim %" PetscInt_FMT " total comp %" PetscInt_FMT "\n", ds->totDim, ds->totComp));
    121:   if (ds->isCohesive) PetscCall(PetscViewerASCIIPrintf(viewer, "  cohesive cell\n"));
    122:   for (f = 0; f < Nf; ++f) {
    123:     DSBoundary      b;
    124:     PetscObject     obj;
    125:     PetscClassId    id;
    126:     PetscQuadrature q;
    127:     const char     *name;
    128:     PetscInt        Nc, Nq, Nqc;

    130:     PetscCall(PetscDSGetDiscretization(ds, f, &obj));
    131:     PetscCall(PetscObjectGetClassId(obj, &id));
    132:     PetscCall(PetscObjectGetName(obj, &name));
    133:     PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s", name ? name : "<unknown>"));
    134:     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
    135:     if (id == PETSCFE_CLASSID) {
    136:       PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
    137:       PetscCall(PetscFEGetQuadrature((PetscFE)obj, &q));
    138:       PetscCall(PetscViewerASCIIPrintf(viewer, " FEM"));
    139:     } else if (id == PETSCFV_CLASSID) {
    140:       PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
    141:       PetscCall(PetscFVGetQuadrature((PetscFV)obj, &q));
    142:       PetscCall(PetscViewerASCIIPrintf(viewer, " FVM"));
    143:     } else SETERRQ(PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
    144:     if (Nc > 1) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " components", Nc));
    145:     else PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " component ", Nc));
    146:     if (ds->implicit[f]) PetscCall(PetscViewerASCIIPrintf(viewer, " (implicit)"));
    147:     else PetscCall(PetscViewerASCIIPrintf(viewer, " (explicit)"));
    148:     if (q) {
    149:       PetscCall(PetscQuadratureGetData(q, NULL, &Nqc, &Nq, NULL, NULL));
    150:       PetscCall(PetscViewerASCIIPrintf(viewer, " (Nq %" PetscInt_FMT " Nqc %" PetscInt_FMT ")", Nq, Nqc));
    151:     }
    152:     PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "-jet", ds->jetDegree[f]));
    153:     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
    154:     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
    155:     PetscCall(PetscViewerASCIIPushTab(viewer));
    156:     if (id == PETSCFE_CLASSID) PetscCall(PetscFEView((PetscFE)obj, viewer));
    157:     else if (id == PETSCFV_CLASSID) PetscCall(PetscFVView((PetscFV)obj, viewer));
    158:     PetscCall(PetscViewerASCIIPopTab(viewer));

    160:     for (b = ds->boundary; b; b = b->next) {
    161:       char    *name;
    162:       PetscInt c, i;

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

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

    224:   Collective

    226:   Input Parameters:
    227: + A    - the `PetscDS` object
    228: . obj  - Optional object that provides the options prefix used in the search of the options database
    229: - name - command line option

    231:   Options Database Key:
    232: . -name [viewertype][:...] - option name and values. See `PetscObjectViewFromOptions()` for the possible arguments

    234:   Level: intermediate

    236: .seealso: `PetscDSType`, `PetscDS`, `PetscDSView()`, `PetscObjectViewFromOptions()`, `PetscDSCreate()`
    237: @*/
    238: PetscErrorCode PetscDSViewFromOptions(PetscDS A, PetscObject obj, const char name[])
    239: {
    240:   PetscFunctionBegin;
    242:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
    243:   PetscFunctionReturn(PETSC_SUCCESS);
    244: }

    246: /*@
    247:   PetscDSView - Views a `PetscDS`

    249:   Collective

    251:   Input Parameters:
    252: + prob - the `PetscDS` object to view
    253: - v    - the viewer

    255:   Level: developer

    257: .seealso: `PetscDSType`, `PetscDS`, `PetscViewer`, `PetscDSDestroy()`, `PetscDSViewFromOptions()`
    258: @*/
    259: PetscErrorCode PetscDSView(PetscDS prob, PetscViewer v)
    260: {
    261:   PetscBool isascii;

    263:   PetscFunctionBegin;
    265:   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)prob), &v));
    267:   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &isascii));
    268:   if (isascii) PetscCall(PetscDSView_Ascii(prob, v));
    269:   PetscTryTypeMethod(prob, view, v);
    270:   PetscFunctionReturn(PETSC_SUCCESS);
    271: }

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

    276:   Collective

    278:   Input Parameter:
    279: . prob - the `PetscDS` object to set options for

    281:   Options Database Keys:
    282: + -petscds_type type            - Set the `PetscDS` type
    283: . -petscds_view                 - View the `PetscDS`
    284: . -petscds_jac_pre (true|false) - Turn formation of a separate Jacobian preconditioner on or off
    285: . -bc_NAME ids                  - comma separated list of label ids for the boundary condition NAME
    286: - -bc_NAME_comp comps           - comma separated list of field components to constrain for the boundary condition NAME

    288:   Level: intermediate

    290: .seealso: `PetscDS`, `PetscDSView()`
    291: @*/
    292: PetscErrorCode PetscDSSetFromOptions(PetscDS prob)
    293: {
    294:   DSBoundary  b;
    295:   const char *defaultType;
    296:   char        name[256];
    297:   PetscBool   flg;

    299:   PetscFunctionBegin;
    301:   if (!((PetscObject)prob)->type_name) {
    302:     defaultType = PETSCDSBASIC;
    303:   } else {
    304:     defaultType = ((PetscObject)prob)->type_name;
    305:   }
    306:   PetscCall(PetscDSRegisterAll());

    308:   PetscObjectOptionsBegin((PetscObject)prob);
    309:   for (b = prob->boundary; b; b = b->next) {
    310:     char      optname[1024];
    311:     PetscInt  ids[1024], len = 1024;
    312:     PetscBool flg;

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

    352: /*@
    353:   PetscDSSetUp - Construct data structures for the `PetscDS`

    355:   Collective

    357:   Input Parameter:
    358: . prob - the `PetscDS` object to setup

    360:   Level: developer

    362: .seealso: `PetscDS`, `PetscDSView()`, `PetscDSDestroy()`
    363: @*/
    364: PetscErrorCode PetscDSSetUp(PetscDS prob)
    365: {
    366:   const PetscInt Nf          = prob->Nf;
    367:   PetscBool      hasH        = PETSC_FALSE;
    368:   PetscInt       maxOrder[4] = {-2, -2, -2, -2};
    369:   PetscInt       dim, dimEmbed, NbMax = 0, NcMax = 0, NqMax = 0, NsMax = 1, f;

    371:   PetscFunctionBegin;
    373:   if (prob->setup) PetscFunctionReturn(PETSC_SUCCESS);
    374:   /* Calculate sizes */
    375:   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
    376:   PetscCall(PetscDSGetCoordinateDimension(prob, &dimEmbed));
    377:   prob->totDim = prob->totComp = 0;
    378:   PetscCall(PetscMalloc2(Nf, &prob->Nc, Nf, &prob->Nb));
    379:   PetscCall(PetscCalloc2(Nf + 1, &prob->off, Nf + 1, &prob->offDer));
    380:   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]));
    381:   PetscCall(PetscMalloc2(Nf, &prob->T, Nf, &prob->Tf));
    382:   if (prob->forceQuad) {
    383:     // Note: This assumes we have one kind of cell at each dimension.
    384:     //       We can fix this by having quadrature hold the celltype
    385:     PetscQuadrature maxQuad[4] = {NULL, NULL, NULL, NULL};

    387:     for (f = 0; f < Nf; ++f) {
    388:       PetscObject     obj;
    389:       PetscClassId    id;
    390:       PetscQuadrature q = NULL, fq = NULL;
    391:       PetscInt        dim = -1, order = -1, forder = -1;

    393:       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
    394:       if (!obj) continue;
    395:       PetscCall(PetscObjectGetClassId(obj, &id));
    396:       if (id == PETSCFE_CLASSID) {
    397:         PetscFE fe = (PetscFE)obj;

    399:         PetscCall(PetscFEGetQuadrature(fe, &q));
    400:         PetscCall(PetscFEGetFaceQuadrature(fe, &fq));
    401:       } else if (id == PETSCFV_CLASSID) {
    402:         PetscFV fv = (PetscFV)obj;

    404:         PetscCall(PetscFVGetQuadrature(fv, &q));
    405:       }
    406:       if (q) {
    407:         PetscCall(PetscQuadratureGetData(q, &dim, NULL, NULL, NULL, NULL));
    408:         PetscCall(PetscQuadratureGetOrder(q, &order));
    409:         if (order > maxOrder[dim]) {
    410:           maxOrder[dim] = order;
    411:           maxQuad[dim]  = q;
    412:         }
    413:       }
    414:       if (fq) {
    415:         PetscCall(PetscQuadratureGetData(fq, &dim, NULL, NULL, NULL, NULL));
    416:         PetscCall(PetscQuadratureGetOrder(fq, &forder));
    417:         if (forder > maxOrder[dim]) {
    418:           maxOrder[dim] = forder;
    419:           maxQuad[dim]  = fq;
    420:         }
    421:       }
    422:     }
    423:     for (f = 0; f < Nf; ++f) {
    424:       PetscObject     obj;
    425:       PetscClassId    id;
    426:       PetscQuadrature q;
    427:       PetscInt        dim;

    429:       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
    430:       if (!obj) continue;
    431:       PetscCall(PetscObjectGetClassId(obj, &id));
    432:       if (id == PETSCFE_CLASSID) {
    433:         PetscFE fe = (PetscFE)obj;

    435:         PetscCall(PetscFEGetQuadrature(fe, &q));
    436:         PetscCall(PetscQuadratureGetData(q, &dim, NULL, NULL, NULL, NULL));
    437:         PetscCall(PetscFESetQuadrature(fe, maxQuad[dim]));
    438:         PetscCall(PetscFESetFaceQuadrature(fe, dim ? maxQuad[dim - 1] : NULL));
    439:       } else if (id == PETSCFV_CLASSID) {
    440:         PetscFV fv = (PetscFV)obj;

    442:         PetscCall(PetscFVGetQuadrature(fv, &q));
    443:         PetscCall(PetscQuadratureGetData(q, &dim, NULL, NULL, NULL, NULL));
    444:         PetscCall(PetscFVSetQuadrature(fv, maxQuad[dim]));
    445:       }
    446:     }
    447:   }
    448:   for (f = 0; f < Nf; ++f) {
    449:     PetscObject     obj;
    450:     PetscClassId    id;
    451:     PetscQuadrature q  = NULL;
    452:     PetscInt        Nq = 0, Nb, Nc;

    454:     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
    455:     if (prob->jetDegree[f] > 1) hasH = PETSC_TRUE;
    456:     if (!obj) {
    457:       /* Empty mesh */
    458:       Nb = Nc    = 0;
    459:       prob->T[f] = prob->Tf[f] = NULL;
    460:     } else {
    461:       PetscCall(PetscObjectGetClassId(obj, &id));
    462:       if (id == PETSCFE_CLASSID) {
    463:         PetscFE fe = (PetscFE)obj;

    465:         PetscCall(PetscFEGetQuadrature(fe, &q));
    466:         {
    467:           PetscQuadrature fq;
    468:           PetscInt        dim, order;

    470:           PetscCall(PetscQuadratureGetData(q, &dim, NULL, NULL, NULL, NULL));
    471:           PetscCall(PetscQuadratureGetOrder(q, &order));
    472:           if (maxOrder[dim] < 0) maxOrder[dim] = order;
    473:           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]);
    474:           PetscCall(PetscFEGetFaceQuadrature(fe, &fq));
    475:           if (fq) {
    476:             PetscCall(PetscQuadratureGetData(fq, &dim, NULL, NULL, NULL, NULL));
    477:             PetscCall(PetscQuadratureGetOrder(fq, &order));
    478:             if (maxOrder[dim] < 0) maxOrder[dim] = order;
    479:             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]);
    480:           }
    481:         }
    482:         PetscCall(PetscFEGetDimension(fe, &Nb));
    483:         PetscCall(PetscFEGetNumComponents(fe, &Nc));
    484:         PetscCall(PetscFEGetCellTabulation(fe, prob->jetDegree[f], &prob->T[f]));
    485:         PetscCall(PetscFEGetFaceTabulation(fe, prob->jetDegree[f], &prob->Tf[f]));
    486:       } else if (id == PETSCFV_CLASSID) {
    487:         PetscFV fv = (PetscFV)obj;

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

    528: static PetscErrorCode PetscDSDestroyStructs_Static(PetscDS prob)
    529: {
    530:   PetscFunctionBegin;
    531:   PetscCall(PetscFree2(prob->Nc, prob->Nb));
    532:   PetscCall(PetscFree2(prob->off, prob->offDer));
    533:   PetscCall(PetscFree6(prob->offCohesive[0], prob->offCohesive[1], prob->offCohesive[2], prob->offDerCohesive[0], prob->offDerCohesive[1], prob->offDerCohesive[2]));
    534:   PetscCall(PetscFree2(prob->T, prob->Tf));
    535:   PetscCall(PetscFree3(prob->u, prob->u_t, prob->u_x));
    536:   PetscCall(PetscFree5(prob->x, prob->basisReal, prob->basisDerReal, prob->testReal, prob->testDerReal));
    537:   PetscCall(PetscFree6(prob->f0, prob->f1, prob->g0, prob->g1, prob->g2, prob->g3));
    538:   PetscFunctionReturn(PETSC_SUCCESS);
    539: }

    541: static PetscErrorCode PetscDSEnlarge_Static(PetscDS prob, PetscInt NfNew)
    542: {
    543:   PetscObject         *tmpd;
    544:   PetscBool           *tmpi;
    545:   PetscInt            *tmpk;
    546:   PetscBool           *tmpc;
    547:   PetscPointFn       **tmpup;
    548:   PetscSimplePointFn **tmpexactSol, **tmpexactSol_t, **tmplowerBound, **tmpupperBound;
    549:   void               **tmpexactCtx, **tmpexactCtx_t, **tmplowerCtx, **tmpupperCtx;
    550:   void               **tmpctx;
    551:   PetscInt             Nf = prob->Nf, f;

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

    615: /*@
    616:   PetscDSDestroy - Destroys a `PetscDS` object

    618:   Collective

    620:   Input Parameter:
    621: . ds - the `PetscDS` object to destroy

    623:   Level: developer

    625: .seealso: `PetscDSView()`
    626: @*/
    627: PetscErrorCode PetscDSDestroy(PetscDS *ds)
    628: {
    629:   PetscInt f;

    631:   PetscFunctionBegin;
    632:   if (!*ds) PetscFunctionReturn(PETSC_SUCCESS);

    635:   if (--((PetscObject)*ds)->refct > 0) {
    636:     *ds = NULL;
    637:     PetscFunctionReturn(PETSC_SUCCESS);
    638:   }
    639:   ((PetscObject)*ds)->refct = 0;
    640:   if ((*ds)->subprobs) {
    641:     PetscInt dim, d;

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

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

    671:   Collective

    673:   Input Parameter:
    674: . comm - The communicator for the `PetscDS` object

    676:   Output Parameter:
    677: . ds - The `PetscDS` object

    679:   Level: beginner

    681: .seealso: `PetscDS`, `PetscDSSetType()`, `PETSCDSBASIC`, `PetscDSType`, `PetscDSDestroy()`
    682: @*/
    683: PetscErrorCode PetscDSCreate(MPI_Comm comm, PetscDS *ds)
    684: {
    685:   PetscDS p;

    687:   PetscFunctionBegin;
    688:   PetscAssertPointer(ds, 2);
    689:   PetscCall(PetscDSInitializePackage());

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

    706: /*@
    707:   PetscDSGetNumFields - Returns the number of fields in the `PetscDS`

    709:   Not Collective

    711:   Input Parameter:
    712: . prob - The `PetscDS` object

    714:   Output Parameter:
    715: . Nf - The number of fields

    717:   Level: beginner

    719: .seealso: `PetscDS`, `PetscDSGetSpatialDimension()`, `PetscDSCreate()`
    720: @*/
    721: PetscErrorCode PetscDSGetNumFields(PetscDS prob, PetscInt *Nf)
    722: {
    723:   PetscFunctionBegin;
    725:   PetscAssertPointer(Nf, 2);
    726:   *Nf = prob->Nf;
    727:   PetscFunctionReturn(PETSC_SUCCESS);
    728: }

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

    733:   Not Collective

    735:   Input Parameter:
    736: . prob - The `PetscDS` object

    738:   Output Parameter:
    739: . dim - The spatial dimension

    741:   Level: beginner

    743: .seealso: `PetscDS`, `PetscDSGetCoordinateDimension()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    744: @*/
    745: PetscErrorCode PetscDSGetSpatialDimension(PetscDS prob, PetscInt *dim)
    746: {
    747:   PetscFunctionBegin;
    749:   PetscAssertPointer(dim, 2);
    750:   *dim = 0;
    751:   if (prob->Nf) {
    752:     PetscObject  obj;
    753:     PetscClassId id;

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

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

    769:   Not Collective

    771:   Input Parameter:
    772: . prob - The `PetscDS` object

    774:   Output Parameter:
    775: . dimEmbed - The coordinate dimension

    777:   Level: beginner

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

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

    794:   Logically Collective

    796:   Input Parameters:
    797: + prob     - The `PetscDS` object
    798: - dimEmbed - The coordinate dimension

    800:   Level: beginner

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

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

    816:   Not collective

    818:   Input Parameter:
    819: . ds - The `PetscDS` object

    821:   Output Parameter:
    822: . forceQuad - The flag

    824:   Level: intermediate

    826: .seealso: `PetscDS`, `PetscDSSetForceQuad()`, `PetscDSGetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    827: @*/
    828: PetscErrorCode PetscDSGetForceQuad(PetscDS ds, PetscBool *forceQuad)
    829: {
    830:   PetscFunctionBegin;
    832:   PetscAssertPointer(forceQuad, 2);
    833:   *forceQuad = ds->forceQuad;
    834:   PetscFunctionReturn(PETSC_SUCCESS);
    835: }

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

    840:   Logically collective on ds

    842:   Input Parameters:
    843: + ds        - The `PetscDS` object
    844: - forceQuad - The flag

    846:   Level: intermediate

    848: .seealso: `PetscDS`, `PetscDSGetForceQuad()`, `PetscDSGetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    849: @*/
    850: PetscErrorCode PetscDSSetForceQuad(PetscDS ds, PetscBool forceQuad)
    851: {
    852:   PetscFunctionBegin;
    854:   ds->forceQuad = forceQuad;
    855:   PetscFunctionReturn(PETSC_SUCCESS);
    856: }

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

    861:   Not Collective

    863:   Input Parameter:
    864: . ds - The `PetscDS` object

    866:   Output Parameter:
    867: . isCohesive - The flag

    869:   Level: developer

    871: .seealso: `PetscDS`, `PetscDSGetNumCohesive()`, `PetscDSGetCohesive()`, `PetscDSSetCohesive()`, `PetscDSCreate()`
    872: @*/
    873: PetscErrorCode PetscDSIsCohesive(PetscDS ds, PetscBool *isCohesive)
    874: {
    875:   PetscFunctionBegin;
    877:   PetscAssertPointer(isCohesive, 2);
    878:   *isCohesive = ds->isCohesive;
    879:   PetscFunctionReturn(PETSC_SUCCESS);
    880: }

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

    885:   Not Collective

    887:   Input Parameter:
    888: . ds - The `PetscDS` object

    890:   Output Parameter:
    891: . numCohesive - The number of cohesive fields

    893:   Level: developer

    895: .seealso: `PetscDS`, `PetscDSSetCohesive()`, `PetscDSCreate()`
    896: @*/
    897: PetscErrorCode PetscDSGetNumCohesive(PetscDS ds, PetscInt *numCohesive)
    898: {
    899:   PetscInt f;

    901:   PetscFunctionBegin;
    903:   PetscAssertPointer(numCohesive, 2);
    904:   *numCohesive = 0;
    905:   for (f = 0; f < ds->Nf; ++f) *numCohesive += ds->cohesive[f] ? 1 : 0;
    906:   PetscFunctionReturn(PETSC_SUCCESS);
    907: }

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

    912:   Not Collective

    914:   Input Parameters:
    915: + ds - The `PetscDS` object
    916: - f  - The field index

    918:   Output Parameter:
    919: . isCohesive - The flag

    921:   Level: developer

    923: .seealso: `PetscDS`, `PetscDSSetCohesive()`, `PetscDSIsCohesive()`, `PetscDSCreate()`
    924: @*/
    925: PetscErrorCode PetscDSGetCohesive(PetscDS ds, PetscInt f, PetscBool *isCohesive)
    926: {
    927:   PetscFunctionBegin;
    929:   PetscAssertPointer(isCohesive, 3);
    930:   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);
    931:   *isCohesive = ds->cohesive[f];
    932:   PetscFunctionReturn(PETSC_SUCCESS);
    933: }

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

    938:   Not Collective

    940:   Input Parameters:
    941: + ds         - The `PetscDS` object
    942: . f          - The field index
    943: - isCohesive - The flag for a cohesive field

    945:   Level: developer

    947: .seealso: `PetscDS`, `PetscDSGetCohesive()`, `PetscDSIsCohesive()`, `PetscDSCreate()`
    948: @*/
    949: PetscErrorCode PetscDSSetCohesive(PetscDS ds, PetscInt f, PetscBool isCohesive)
    950: {
    951:   PetscInt i;

    953:   PetscFunctionBegin;
    955:   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);
    956:   ds->cohesive[f] = isCohesive;
    957:   ds->isCohesive  = PETSC_FALSE;
    958:   for (i = 0; i < ds->Nf; ++i) ds->isCohesive = ds->isCohesive || ds->cohesive[f] ? PETSC_TRUE : PETSC_FALSE;
    959:   PetscFunctionReturn(PETSC_SUCCESS);
    960: }

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

    965:   Not Collective

    967:   Input Parameter:
    968: . prob - The `PetscDS` object

    970:   Output Parameter:
    971: . dim - The total problem dimension

    973:   Level: beginner

    975: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    976: @*/
    977: PetscErrorCode PetscDSGetTotalDimension(PetscDS prob, PetscInt *dim)
    978: {
    979:   PetscFunctionBegin;
    981:   PetscCall(PetscDSSetUp(prob));
    982:   PetscAssertPointer(dim, 2);
    983:   *dim = prob->totDim;
    984:   PetscFunctionReturn(PETSC_SUCCESS);
    985: }

    987: /*@
    988:   PetscDSGetTotalComponents - Returns the total number of components in this system

    990:   Not Collective

    992:   Input Parameter:
    993: . prob - The `PetscDS` object

    995:   Output Parameter:
    996: . Nc - The total number of components

    998:   Level: beginner

    1000: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1001: @*/
    1002: PetscErrorCode PetscDSGetTotalComponents(PetscDS prob, PetscInt *Nc)
    1003: {
    1004:   PetscFunctionBegin;
    1006:   PetscCall(PetscDSSetUp(prob));
    1007:   PetscAssertPointer(Nc, 2);
    1008:   *Nc = prob->totComp;
    1009:   PetscFunctionReturn(PETSC_SUCCESS);
    1010: }

    1012: /*@
    1013:   PetscDSGetDiscretization - Returns the discretization object for the given field

    1015:   Not Collective

    1017:   Input Parameters:
    1018: + prob - The `PetscDS` object
    1019: - f    - The field number

    1021:   Output Parameter:
    1022: . disc - The discretization object, this can be a `PetscFE` or a `PetscFV`

    1024:   Level: beginner

    1026: .seealso: `PetscDS`, `PetscFE`, `PetscFV`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1027: @*/
    1028: PetscErrorCode PetscDSGetDiscretization(PetscDS prob, PetscInt f, PetscObject *disc)
    1029: {
    1030:   PetscFunctionBeginHot;
    1032:   PetscAssertPointer(disc, 3);
    1033:   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);
    1034:   *disc = prob->disc[f];
    1035:   PetscFunctionReturn(PETSC_SUCCESS);
    1036: }

    1038: /*@
    1039:   PetscDSSetDiscretization - Sets the discretization object for the given field

    1041:   Not Collective

    1043:   Input Parameters:
    1044: + prob - The `PetscDS` object
    1045: . f    - The field number
    1046: - disc - The discretization object, this can be a `PetscFE` or a `PetscFV`

    1048:   Level: beginner

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

    1065:     PetscCall(PetscObjectGetClassId(disc, &id));
    1066:     if (id == PETSCFE_CLASSID) {
    1067:       PetscCall(PetscDSSetImplicit(prob, f, PETSC_TRUE));
    1068:     } else if (id == PETSCFV_CLASSID) {
    1069:       PetscCall(PetscDSSetImplicit(prob, f, PETSC_FALSE));
    1070:     }
    1071:     PetscCall(PetscDSSetJetDegree(prob, f, 1));
    1072:   }
    1073:   PetscFunctionReturn(PETSC_SUCCESS);
    1074: }

    1076: /*@
    1077:   PetscDSGetWeakForm - Returns the weak form object from within the `PetscDS`

    1079:   Not Collective

    1081:   Input Parameter:
    1082: . ds - The `PetscDS` object

    1084:   Output Parameter:
    1085: . wf - The weak form object

    1087:   Level: beginner

    1089: .seealso: `PetscWeakForm`, `PetscDSSetWeakForm()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1090: @*/
    1091: PetscErrorCode PetscDSGetWeakForm(PetscDS ds, PetscWeakForm *wf)
    1092: {
    1093:   PetscFunctionBegin;
    1095:   PetscAssertPointer(wf, 2);
    1096:   *wf = ds->wf;
    1097:   PetscFunctionReturn(PETSC_SUCCESS);
    1098: }

    1100: /*@
    1101:   PetscDSSetWeakForm - Sets the weak form object to be used by the `PetscDS`

    1103:   Not Collective

    1105:   Input Parameters:
    1106: + ds - The `PetscDS` object
    1107: - wf - The weak form object

    1109:   Level: beginner

    1111: .seealso: `PetscWeakForm`, `PetscDSGetWeakForm()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1112: @*/
    1113: PetscErrorCode PetscDSSetWeakForm(PetscDS ds, PetscWeakForm wf)
    1114: {
    1115:   PetscFunctionBegin;
    1118:   PetscCall(PetscObjectDereference((PetscObject)ds->wf));
    1119:   ds->wf = wf;
    1120:   PetscCall(PetscObjectReference((PetscObject)wf));
    1121:   PetscCall(PetscWeakFormSetNumFields(wf, ds->Nf));
    1122:   PetscFunctionReturn(PETSC_SUCCESS);
    1123: }

    1125: /*@
    1126:   PetscDSAddDiscretization - Adds a discretization object

    1128:   Not Collective

    1130:   Input Parameters:
    1131: + prob - The `PetscDS` object
    1132: - disc - The discretization object, this can be a `PetscFE` or `PetscFV`

    1134:   Level: beginner

    1136: .seealso: `PetscWeakForm`, `PetscFE`, `PetscFV`, `PetscDSGetDiscretization()`, `PetscDSSetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1137: @*/
    1138: PetscErrorCode PetscDSAddDiscretization(PetscDS prob, PetscObject disc)
    1139: {
    1140:   PetscFunctionBegin;
    1141:   PetscCall(PetscDSSetDiscretization(prob, prob->Nf, disc));
    1142:   PetscFunctionReturn(PETSC_SUCCESS);
    1143: }

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

    1148:   Not Collective

    1150:   Input Parameter:
    1151: . prob - The `PetscDS` object

    1153:   Output Parameter:
    1154: . q - The quadrature object

    1156:   Level: intermediate

    1158: .seealso: `PetscDS`, `PetscQuadrature`, `PetscDSSetImplicit()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1159: @*/
    1160: PetscErrorCode PetscDSGetQuadrature(PetscDS prob, PetscQuadrature *q)
    1161: {
    1162:   PetscObject  obj;
    1163:   PetscClassId id;

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

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

    1179:   Not Collective

    1181:   Input Parameters:
    1182: + prob - The `PetscDS` object
    1183: - f    - The field number

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

    1188:   Level: developer

    1190: .seealso: `TSARKIMEX`, `PetscDS`, `PetscDSSetImplicit()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1191: @*/
    1192: PetscErrorCode PetscDSGetImplicit(PetscDS prob, PetscInt f, PetscBool *implicit)
    1193: {
    1194:   PetscFunctionBegin;
    1196:   PetscAssertPointer(implicit, 3);
    1197:   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);
    1198:   *implicit = prob->implicit[f];
    1199:   PetscFunctionReturn(PETSC_SUCCESS);
    1200: }

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

    1205:   Not Collective

    1207:   Input Parameters:
    1208: + prob     - The `PetscDS` object
    1209: . f        - The field number
    1210: - implicit - The flag indicating what kind of solve to use for this field

    1212:   Level: developer

    1214: .seealso: `TSARKIMEX`, `PetscDSGetImplicit()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1215: @*/
    1216: PetscErrorCode PetscDSSetImplicit(PetscDS prob, PetscInt f, PetscBool implicit)
    1217: {
    1218:   PetscFunctionBegin;
    1220:   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);
    1221:   prob->implicit[f] = implicit;
    1222:   PetscFunctionReturn(PETSC_SUCCESS);
    1223: }

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

    1228:   Not Collective

    1230:   Input Parameters:
    1231: + ds - The `PetscDS` object
    1232: - f  - The field number

    1234:   Output Parameter:
    1235: . k - The highest derivative we need to tabulate

    1237:   Level: developer

    1239: .seealso: `PetscDS`, `PetscDSSetJetDegree()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1240: @*/
    1241: PetscErrorCode PetscDSGetJetDegree(PetscDS ds, PetscInt f, PetscInt *k)
    1242: {
    1243:   PetscFunctionBegin;
    1245:   PetscAssertPointer(k, 3);
    1246:   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);
    1247:   *k = ds->jetDegree[f];
    1248:   PetscFunctionReturn(PETSC_SUCCESS);
    1249: }

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

    1254:   Not Collective

    1256:   Input Parameters:
    1257: + ds - The `PetscDS` object
    1258: . f  - The field number
    1259: - k  - The highest derivative we need to tabulate

    1261:   Level: developer

    1263: .seealso: `PetscDS`, `PetscDSGetJetDegree()`, `PetscDSSetDiscretization()`, `PetscDSAddDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    1264: @*/
    1265: PetscErrorCode PetscDSSetJetDegree(PetscDS ds, PetscInt f, PetscInt k)
    1266: {
    1267:   PetscFunctionBegin;
    1269:   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);
    1270:   ds->jetDegree[f] = k;
    1271:   PetscFunctionReturn(PETSC_SUCCESS);
    1272: }

    1274: /*@C
    1275:   PetscDSGetObjective - Get the pointwise objective function for a given test field that was provided with `PetscDSSetObjective()`

    1277:   Not Collective

    1279:   Input Parameters:
    1280: + ds - The `PetscDS`
    1281: - f  - The test field number

    1283:   Output Parameter:
    1284: . obj - integrand for the test function term, see `PetscPointFn`

    1286:   Level: intermediate

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

    1291: .seealso: `PetscPointFn`, `PetscDS`, `PetscDSSetObjective()`, `PetscDSGetResidual()`
    1292: @*/
    1293: PetscErrorCode PetscDSGetObjective(PetscDS ds, PetscInt f, PetscPointFn **obj)
    1294: {
    1295:   PetscPointFn **tmp;
    1296:   PetscInt       n;

    1298:   PetscFunctionBegin;
    1300:   PetscAssertPointer(obj, 3);
    1301:   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);
    1302:   PetscCall(PetscWeakFormGetObjective(ds->wf, NULL, 0, f, 0, &n, &tmp));
    1303:   *obj = tmp ? tmp[0] : NULL;
    1304:   PetscFunctionReturn(PETSC_SUCCESS);
    1305: }

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

    1310:   Not Collective

    1312:   Input Parameters:
    1313: + ds  - The `PetscDS`
    1314: . f   - The test field number
    1315: - obj - integrand for the test function term, see `PetscPointFn`

    1317:   Level: intermediate

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

    1322: .seealso: `PetscPointFn`, `PetscDS`, `PetscDSGetObjective()`, `PetscDSSetResidual()`
    1323: @*/
    1324: PetscErrorCode PetscDSSetObjective(PetscDS ds, PetscInt f, PetscPointFn *obj)
    1325: {
    1326:   PetscFunctionBegin;
    1329:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1330:   PetscCall(PetscWeakFormSetIndexObjective(ds->wf, NULL, 0, f, 0, 0, obj));
    1331:   PetscFunctionReturn(PETSC_SUCCESS);
    1332: }

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

    1337:   Not Collective

    1339:   Input Parameters:
    1340: + ds - The `PetscDS`
    1341: - f  - The test field number

    1343:   Output Parameters:
    1344: + f0 - integrand for the test function term, see `PetscPointFn`
    1345: - f1 - integrand for the test function gradient term, see `PetscPointFn`

    1347:   Level: intermediate

    1349:   Note:
    1350:   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)$

    1352: .seealso: `PetscPointFn`, `PetscDS`, `PetscDSSetResidual()`
    1353: @*/
    1354: PetscErrorCode PetscDSGetResidual(PetscDS ds, PetscInt f, PetscPointFn **f0, PetscPointFn **f1)
    1355: {
    1356:   PetscPointFn **tmp0, **tmp1;
    1357:   PetscInt       n0, n1;

    1359:   PetscFunctionBegin;
    1361:   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);
    1362:   PetscCall(PetscWeakFormGetResidual(ds->wf, NULL, 0, f, 0, &n0, &tmp0, &n1, &tmp1));
    1363:   *f0 = tmp0 ? tmp0[0] : NULL;
    1364:   *f1 = tmp1 ? tmp1[0] : NULL;
    1365:   PetscFunctionReturn(PETSC_SUCCESS);
    1366: }

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

    1371:   Not Collective

    1373:   Input Parameters:
    1374: + ds - The `PetscDS`
    1375: . f  - The test field number
    1376: . f0 - integrand for the test function term, see `PetscPointFn`
    1377: - f1 - integrand for the test function gradient term, see `PetscPointFn`

    1379:   Level: intermediate

    1381:   Note:
    1382:   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)$

    1384: .seealso: `PetscPointFn`, `PetscDS`, `PetscDSGetResidual()`
    1385: @*/
    1386: PetscErrorCode PetscDSSetResidual(PetscDS ds, PetscInt f, PetscPointFn *f0, PetscPointFn *f1)
    1387: {
    1388:   PetscFunctionBegin;
    1392:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1393:   PetscCall(PetscWeakFormSetIndexResidual(ds->wf, NULL, 0, f, 0, 0, f0, 0, f1));
    1394:   PetscFunctionReturn(PETSC_SUCCESS);
    1395: }

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

    1400:   Not Collective

    1402:   Input Parameters:
    1403: + ds - The `PetscDS`
    1404: - f  - The test field number

    1406:   Output Parameters:
    1407: + f0 - integrand for the test function term, see `PetscPointFn`
    1408: - f1 - integrand for the test function gradient term, see `PetscPointFn`

    1410:   Level: intermediate

    1412:   Note:
    1413:   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)$

    1415: .seealso: `PetscPointFn`, `PetscDS`, `PetscDSSetRHSResidual()`
    1416: @*/
    1417: PetscErrorCode PetscDSGetRHSResidual(PetscDS ds, PetscInt f, PetscPointFn **f0, PetscPointFn **f1)
    1418: {
    1419:   PetscPointFn **tmp0, **tmp1;
    1420:   PetscInt       n0, n1;

    1422:   PetscFunctionBegin;
    1424:   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);
    1425:   PetscCall(PetscWeakFormGetResidual(ds->wf, NULL, 0, f, 100, &n0, &tmp0, &n1, &tmp1));
    1426:   *f0 = tmp0 ? tmp0[0] : NULL;
    1427:   *f1 = tmp1 ? tmp1[0] : NULL;
    1428:   PetscFunctionReturn(PETSC_SUCCESS);
    1429: }

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

    1434:   Not Collective

    1436:   Input Parameters:
    1437: + ds - The `PetscDS`
    1438: . f  - The test field number
    1439: . f0 - integrand for the test function term, see `PetscPointFn`
    1440: - f1 - integrand for the test function gradient term, see `PetscPointFn`

    1442:   Level: intermediate

    1444:   Note:
    1445:   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)$

    1447: .seealso: `PetscDS`, `PetscDSGetResidual()`
    1448: @*/
    1449: PetscErrorCode PetscDSSetRHSResidual(PetscDS ds, PetscInt f, PetscPointFn *f0, PetscPointFn *f1)
    1450: {
    1451:   PetscFunctionBegin;
    1455:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1456:   PetscCall(PetscWeakFormSetIndexResidual(ds->wf, NULL, 0, f, 100, 0, f0, 0, f1));
    1457:   PetscFunctionReturn(PETSC_SUCCESS);
    1458: }

    1460: /*@
    1461:   PetscDSHasJacobian - Checks that the Jacobian functions have been set

    1463:   Not Collective

    1465:   Input Parameter:
    1466: . ds - The `PetscDS`

    1468:   Output Parameter:
    1469: . hasJac - flag that indicates the pointwise function for the Jacobian has been set

    1471:   Level: intermediate

    1473: .seealso: `PetscDS`, `PetscDSGetJacobianPreconditioner()`, `PetscDSSetJacobianPreconditioner()`, `PetscDSGetJacobian()`
    1474: @*/
    1475: PetscErrorCode PetscDSHasJacobian(PetscDS ds, PetscBool *hasJac)
    1476: {
    1477:   PetscFunctionBegin;
    1479:   PetscCall(PetscWeakFormHasJacobian(ds->wf, hasJac));
    1480:   PetscFunctionReturn(PETSC_SUCCESS);
    1481: }

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

    1486:   Not Collective

    1488:   Input Parameters:
    1489: + ds - The `PetscDS`
    1490: . f  - The test field number
    1491: - g  - The field number

    1493:   Output Parameters:
    1494: + g0 - integrand for the test and basis function term, see `PetscPointJacFn`
    1495: . g1 - integrand for the test function and basis function gradient term, see `PetscPointJacFn`
    1496: . g2 - integrand for the test function gradient and basis function term, see `PetscPointJacFn`
    1497: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscPointJacFn`

    1499:   Level: intermediate

    1501:   Note:
    1502:   We are using a first order FEM model for the weak form\:

    1504:   $$
    1505:   \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
    1506:   + \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
    1507:   $$

    1509: .seealso: `PetscDS`, `PetscDSSetJacobian()`, `PetscPointJacFn`
    1510: @*/
    1511: PetscErrorCode PetscDSGetJacobian(PetscDS ds, PetscInt f, PetscInt g, PetscPointJacFn **g0, PetscPointJacFn **g1, PetscPointJacFn **g2, PetscPointJacFn **g3)
    1512: {
    1513:   PetscPointJacFn **tmp0, **tmp1, **tmp2, **tmp3;
    1514:   PetscInt          n0, n1, n2, n3;

    1516:   PetscFunctionBegin;
    1518:   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);
    1519:   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);
    1520:   PetscCall(PetscWeakFormGetJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    1521:   *g0 = tmp0 ? tmp0[0] : NULL;
    1522:   *g1 = tmp1 ? tmp1[0] : NULL;
    1523:   *g2 = tmp2 ? tmp2[0] : NULL;
    1524:   *g3 = tmp3 ? tmp3[0] : NULL;
    1525:   PetscFunctionReturn(PETSC_SUCCESS);
    1526: }

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

    1531:   Not Collective

    1533:   Input Parameters:
    1534: + ds - The `PetscDS`
    1535: . f  - The test field number
    1536: . g  - The field number
    1537: . g0 - integrand for the test and basis function term, see `PetscPointJacFn`
    1538: . g1 - integrand for the test function and basis function gradient term, see `PetscPointJacFn`
    1539: . g2 - integrand for the test function gradient and basis function term, see `PetscPointJacFn`
    1540: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscPointJacFn`

    1542:   Level: intermediate

    1544:   Note:
    1545:   We are using a first order FEM model for the weak form\:

    1547:   $$
    1548:   \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
    1549:   + \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
    1550:   $$

    1552: .seealso: `PetscDS`, `PetscDSGetJacobian()`, `PetscPointJacFn`
    1553: @*/
    1554: PetscErrorCode PetscDSSetJacobian(PetscDS ds, PetscInt f, PetscInt g, PetscPointJacFn *g0, PetscPointJacFn *g1, PetscPointJacFn *g2, PetscPointJacFn *g3)
    1555: {
    1556:   PetscFunctionBegin;
    1562:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1563:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    1564:   PetscCall(PetscWeakFormSetIndexJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    1565:   PetscFunctionReturn(PETSC_SUCCESS);
    1566: }

    1568: /*@
    1569:   PetscDSUseJacobianPreconditioner - Set whether to construct a Jacobian preconditioner

    1571:   Not Collective

    1573:   Input Parameters:
    1574: + prob      - The `PetscDS`
    1575: - useJacPre - flag that enables construction of a Jacobian preconditioner

    1577:   Level: intermediate

    1579:   Developer Note:
    1580:   Should be called `PetscDSSetUseJacobianPreconditioner()`

    1582: .seealso: `PetscDS`, `PetscDSGetJacobianPreconditioner()`, `PetscDSSetJacobianPreconditioner()`, `PetscDSGetJacobian()`
    1583: @*/
    1584: PetscErrorCode PetscDSUseJacobianPreconditioner(PetscDS prob, PetscBool useJacPre)
    1585: {
    1586:   PetscFunctionBegin;
    1588:   prob->useJacPre = useJacPre;
    1589:   PetscFunctionReturn(PETSC_SUCCESS);
    1590: }

    1592: /*@
    1593:   PetscDSHasJacobianPreconditioner - Checks if a Jacobian matrix for constructing a preconditioner has been set

    1595:   Not Collective

    1597:   Input Parameter:
    1598: . ds - The `PetscDS`

    1600:   Output Parameter:
    1601: . hasJacPre - the flag

    1603:   Level: intermediate

    1605: .seealso: `PetscDS`, `PetscDSGetJacobianPreconditioner()`, `PetscDSSetJacobianPreconditioner()`, `PetscDSGetJacobian()`
    1606: @*/
    1607: PetscErrorCode PetscDSHasJacobianPreconditioner(PetscDS ds, PetscBool *hasJacPre)
    1608: {
    1609:   PetscFunctionBegin;
    1611:   *hasJacPre = PETSC_FALSE;
    1612:   if (!ds->useJacPre) PetscFunctionReturn(PETSC_SUCCESS);
    1613:   PetscCall(PetscWeakFormHasJacobianPreconditioner(ds->wf, hasJacPre));
    1614:   PetscFunctionReturn(PETSC_SUCCESS);
    1615: }

    1617: /*@C
    1618:   PetscDSGetJacobianPreconditioner - Get the pointwise Jacobian function for given test and basis field that constructs the matrix used
    1619:   to compute the preconditioner. If this is missing, the system matrix is used to build the preconditioner.

    1621:   Not Collective

    1623:   Input Parameters:
    1624: + ds - The `PetscDS`
    1625: . f  - The test field number
    1626: - g  - The field number

    1628:   Output Parameters:
    1629: + g0 - integrand for the test and basis function term, see `PetscPointJacFn`
    1630: . g1 - integrand for the test function and basis function gradient term, see `PetscPointJacFn`
    1631: . g2 - integrand for the test function gradient and basis function term, see `PetscPointJacFn`
    1632: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscPointJacFn`

    1634:   Level: intermediate

    1636:   Note:
    1637:   We are using a first order FEM model for the weak form\:

    1639:   $$
    1640:   \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
    1641:   + \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
    1642:   $$

    1644:   Developer Note:
    1645:   The name is confusing since the function computes a matrix used to construct the preconditioner, not a preconditioner.

    1647: .seealso: `PetscDS`, `PetscDSSetJacobianPreconditioner()`, `PetscDSGetJacobian()`, `PetscPointJacFn`
    1648: @*/
    1649: PetscErrorCode PetscDSGetJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g, PetscPointJacFn **g0, PetscPointJacFn **g1, PetscPointJacFn **g2, PetscPointJacFn **g3)
    1650: {
    1651:   PetscPointJacFn **tmp0, **tmp1, **tmp2, **tmp3;
    1652:   PetscInt          n0, n1, n2, n3;

    1654:   PetscFunctionBegin;
    1656:   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);
    1657:   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);
    1658:   PetscCall(PetscWeakFormGetJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    1659:   *g0 = tmp0 ? tmp0[0] : NULL;
    1660:   *g1 = tmp1 ? tmp1[0] : NULL;
    1661:   *g2 = tmp2 ? tmp2[0] : NULL;
    1662:   *g3 = tmp3 ? tmp3[0] : NULL;
    1663:   PetscFunctionReturn(PETSC_SUCCESS);
    1664: }

    1666: /*@C
    1667:   PetscDSSetJacobianPreconditioner - Set the pointwise Jacobian function for given test and basis fields that constructs the matrix used
    1668:   to compute the preconditioner. If this is missing, the system matrix is used to build the preconditioner.

    1670:   Not Collective

    1672:   Input Parameters:
    1673: + ds - The `PetscDS`
    1674: . f  - The test field number
    1675: . g  - The field number
    1676: . g0 - integrand for the test and basis function term, see `PetscPointJacFn`
    1677: . g1 - integrand for the test function and basis function gradient term, see `PetscPointJacFn`
    1678: . g2 - integrand for the test function gradient and basis function term, see `PetscPointJacFn`
    1679: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscPointJacFn`

    1681:   Level: intermediate

    1683:   Note:
    1684:   We are using a first order FEM model for the weak form\:

    1686:   $$
    1687:   \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
    1688:   + \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
    1689:   $$

    1691:   Developer Note:
    1692:   The name is confusing since the function computes a matrix used to construct the preconditioner, not a preconditioner.

    1694: .seealso: `PetscDS`, `PetscDSGetJacobianPreconditioner()`, `PetscDSSetJacobian()`, `PetscPointJacFn`
    1695: @*/
    1696: PetscErrorCode PetscDSSetJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g, PetscPointJacFn *g0, PetscPointJacFn *g1, PetscPointJacFn *g2, PetscPointJacFn *g3)
    1697: {
    1698:   PetscFunctionBegin;
    1704:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1705:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    1706:   PetscCall(PetscWeakFormSetIndexJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    1707:   PetscFunctionReturn(PETSC_SUCCESS);
    1708: }

    1710: /*@
    1711:   PetscDSHasDynamicJacobian - Signals that a dynamic Jacobian, $dF/du_t$, has been set

    1713:   Not Collective

    1715:   Input Parameter:
    1716: . ds - The `PetscDS`

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

    1721:   Level: intermediate

    1723: .seealso: `PetscDS`, `PetscDSGetDynamicJacobian()`, `PetscDSSetDynamicJacobian()`, `PetscDSGetJacobian()`
    1724: @*/
    1725: PetscErrorCode PetscDSHasDynamicJacobian(PetscDS ds, PetscBool *hasDynJac)
    1726: {
    1727:   PetscFunctionBegin;
    1729:   PetscCall(PetscWeakFormHasDynamicJacobian(ds->wf, hasDynJac));
    1730:   PetscFunctionReturn(PETSC_SUCCESS);
    1731: }

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

    1736:   Not Collective

    1738:   Input Parameters:
    1739: + ds - The `PetscDS`
    1740: . f  - The test field number
    1741: - g  - The field number

    1743:   Output Parameters:
    1744: + g0 - integrand for the test and basis function term, see `PetscPointJacFn`
    1745: . g1 - integrand for the test function and basis function gradient term, see `PetscPointJacFn`
    1746: . g2 - integrand for the test function gradient and basis function term, see `PetscPointJacFn`
    1747: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscPointJacFn`

    1749:   Level: intermediate

    1751:   Note:
    1752:   We are using a first order FEM model for the weak form\:

    1754:   $$
    1755:   \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
    1756:   + \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
    1757:   $$

    1759: .seealso: `PetscDS`, `PetscDSSetJacobian()`, `PetscDSSetDynamicJacobian()`, `PetscPointJacFn`
    1760: @*/
    1761: PetscErrorCode PetscDSGetDynamicJacobian(PetscDS ds, PetscInt f, PetscInt g, PetscPointJacFn **g0, PetscPointJacFn **g1, PetscPointJacFn **g2, PetscPointJacFn **g3)
    1762: {
    1763:   PetscPointJacFn **tmp0, **tmp1, **tmp2, **tmp3;
    1764:   PetscInt          n0, n1, n2, n3;

    1766:   PetscFunctionBegin;
    1768:   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);
    1769:   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);
    1770:   PetscCall(PetscWeakFormGetDynamicJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    1771:   *g0 = tmp0 ? tmp0[0] : NULL;
    1772:   *g1 = tmp1 ? tmp1[0] : NULL;
    1773:   *g2 = tmp2 ? tmp2[0] : NULL;
    1774:   *g3 = tmp3 ? tmp3[0] : NULL;
    1775:   PetscFunctionReturn(PETSC_SUCCESS);
    1776: }

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

    1781:   Not Collective

    1783:   Input Parameters:
    1784: + ds - The `PetscDS`
    1785: . f  - The test field number
    1786: . g  - The field number
    1787: . g0 - integrand for the test and basis function term, see `PetscPointJacFn`
    1788: . g1 - integrand for the test function and basis function gradient term, see `PetscPointJacFn`
    1789: . g2 - integrand for the test function gradient and basis function term, see `PetscPointJacFn`
    1790: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscPointJacFn`

    1792:   Level: intermediate

    1794:   Note:
    1795:   We are using a first order FEM model for the weak form\:

    1797:   $$
    1798:   \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
    1799:   + \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
    1800:   $$

    1802: .seealso: `PetscDS`, `PetscDSGetDynamicJacobian()`, `PetscDSGetJacobian()`, `PetscPointJacFn`
    1803: @*/
    1804: PetscErrorCode PetscDSSetDynamicJacobian(PetscDS ds, PetscInt f, PetscInt g, PetscPointJacFn *g0, PetscPointJacFn *g1, PetscPointJacFn *g2, PetscPointJacFn *g3)
    1805: {
    1806:   PetscFunctionBegin;
    1812:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1813:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    1814:   PetscCall(PetscWeakFormSetIndexDynamicJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    1815:   PetscFunctionReturn(PETSC_SUCCESS);
    1816: }

    1818: /*@C
    1819:   PetscDSGetRiemannSolver - Returns the Riemann solver for the given field

    1821:   Not Collective

    1823:   Input Parameters:
    1824: + ds - The `PetscDS` object
    1825: - f  - The field number

    1827:   Output Parameter:
    1828: . r - Riemann solver, see `PetscRiemannFn`

    1830:   Level: intermediate

    1832: .seealso: `PetscDS`, `PetscRiemannFn`, `PetscDSSetRiemannSolver()`
    1833: @*/
    1834: PetscErrorCode PetscDSGetRiemannSolver(PetscDS ds, PetscInt f, PetscRiemannFn **r)
    1835: {
    1836:   PetscRiemannFn **tmp;
    1837:   PetscInt         n;

    1839:   PetscFunctionBegin;
    1841:   PetscAssertPointer(r, 3);
    1842:   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);
    1843:   PetscCall(PetscWeakFormGetRiemannSolver(ds->wf, NULL, 0, f, 0, &n, &tmp));
    1844:   *r = tmp ? tmp[0] : NULL;
    1845:   PetscFunctionReturn(PETSC_SUCCESS);
    1846: }

    1848: /*@C
    1849:   PetscDSSetRiemannSolver - Sets the Riemann solver for the given field

    1851:   Not Collective

    1853:   Input Parameters:
    1854: + ds - The `PetscDS` object
    1855: . f  - The field number
    1856: - r  - Riemann solver, see `PetscRiemannFn`

    1858:   Level: intermediate

    1860: .seealso: `PetscDS`, `PetscRiemannFn`, `PetscDSGetRiemannSolver()`
    1861: @*/
    1862: PetscErrorCode PetscDSSetRiemannSolver(PetscDS ds, PetscInt f, PetscRiemannFn *r)
    1863: {
    1864:   PetscFunctionBegin;
    1867:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1868:   PetscCall(PetscWeakFormSetIndexRiemannSolver(ds->wf, NULL, 0, f, 0, 0, r));
    1869:   PetscFunctionReturn(PETSC_SUCCESS);
    1870: }

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

    1875:   Not Collective

    1877:   Input Parameters:
    1878: + ds - The `PetscDS`
    1879: - f  - The field number

    1881:   Output Parameter:
    1882: . update - update function, see `PetscPointFn`

    1884:   Level: intermediate

    1886: .seealso: `PetscDS`, `PetscPointFn`, `PetscDSSetUpdate()`, `PetscDSSetResidual()`
    1887: @*/
    1888: PetscErrorCode PetscDSGetUpdate(PetscDS ds, PetscInt f, PetscPointFn **update)
    1889: {
    1890:   PetscFunctionBegin;
    1892:   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);
    1893:   if (update) {
    1894:     PetscAssertPointer(update, 3);
    1895:     *update = ds->update[f];
    1896:   }
    1897:   PetscFunctionReturn(PETSC_SUCCESS);
    1898: }

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

    1903:   Not Collective

    1905:   Input Parameters:
    1906: + ds     - The `PetscDS`
    1907: . f      - The field number
    1908: - update - update function, see `PetscPointFn`

    1910:   Level: intermediate

    1912: .seealso: `PetscDS`, `PetscPointFn`, `PetscDSGetResidual()`
    1913: @*/
    1914: PetscErrorCode PetscDSSetUpdate(PetscDS ds, PetscInt f, PetscPointFn *update)
    1915: {
    1916:   PetscFunctionBegin;
    1919:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1920:   PetscCall(PetscDSEnlarge_Static(ds, f + 1));
    1921:   ds->update[f] = update;
    1922:   PetscFunctionReturn(PETSC_SUCCESS);
    1923: }

    1925: /*@C
    1926:   PetscDSGetContext - Returns the context that was passed by `PetscDSSetContext()`

    1928:   Not Collective

    1930:   Input Parameters:
    1931: + ds  - The `PetscDS`
    1932: . f   - The field number
    1933: - ctx - the context

    1935:   Level: intermediate

    1937:   Fortran Notes:
    1938:   This only works when the context is a Fortran derived type or a `PetscObject`. Define `ctx` with
    1939: .vb
    1940:   type(tUsertype), pointer :: ctx
    1941: .ve

    1943: .seealso: `PetscDS`, `PetscPointFn`, `PetscDSSetContext()`
    1944: @*/
    1945: PetscErrorCode PetscDSGetContext(PetscDS ds, PetscInt f, PetscCtxRt ctx)
    1946: {
    1947:   PetscFunctionBegin;
    1949:   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);
    1950:   PetscAssertPointer(ctx, 3);
    1951:   *(void **)ctx = ds->ctx[f];
    1952:   PetscFunctionReturn(PETSC_SUCCESS);
    1953: }

    1955: /*@C
    1956:   PetscDSSetContext - Sets the context that is passed back to some of the pointwise function callbacks used by this `PetscDS`

    1958:   Not Collective

    1960:   Input Parameters:
    1961: + ds  - The `PetscDS`
    1962: . f   - The field number
    1963: - ctx - the context

    1965:   Level: intermediate

    1967: .seealso: `PetscDS`, `PetscPointFn`, `PetscDSGetContext()`
    1968: @*/
    1969: PetscErrorCode PetscDSSetContext(PetscDS ds, PetscInt f, PetscCtx ctx)
    1970: {
    1971:   PetscFunctionBegin;
    1973:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    1974:   PetscCall(PetscDSEnlarge_Static(ds, f + 1));
    1975:   ds->ctx[f] = ctx;
    1976:   PetscFunctionReturn(PETSC_SUCCESS);
    1977: }

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

    1982:   Not Collective

    1984:   Input Parameters:
    1985: + ds - The PetscDS
    1986: - f  - The test field number

    1988:   Output Parameters:
    1989: + f0 - boundary integrand for the test function term, see `PetscBdPointFn`
    1990: - f1 - boundary integrand for the test function gradient term, see `PetscBdPointFn`

    1992:   Level: intermediate

    1994:   Note:
    1995:   We are using a first order FEM model for the weak form\:

    1997:   $$
    1998:   \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
    1999:   $$

    2001: .seealso: `PetscDS`, `PetscBdPointFn`, `PetscDSSetBdResidual()`
    2002: @*/
    2003: PetscErrorCode PetscDSGetBdResidual(PetscDS ds, PetscInt f, PetscBdPointFn **f0, PetscBdPointFn **f1)
    2004: {
    2005:   PetscBdPointFn **tmp0, **tmp1;
    2006:   PetscInt         n0, n1;

    2008:   PetscFunctionBegin;
    2010:   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);
    2011:   PetscCall(PetscWeakFormGetBdResidual(ds->wf, NULL, 0, f, 0, &n0, &tmp0, &n1, &tmp1));
    2012:   *f0 = tmp0 ? tmp0[0] : NULL;
    2013:   *f1 = tmp1 ? tmp1[0] : NULL;
    2014:   PetscFunctionReturn(PETSC_SUCCESS);
    2015: }

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

    2020:   Not Collective

    2022:   Input Parameters:
    2023: + ds - The `PetscDS`
    2024: . f  - The test field number
    2025: . f0 - boundary integrand for the test function term, see `PetscBdPointFn`
    2026: - f1 - boundary integrand for the test function gradient term, see `PetscBdPointFn`

    2028:   Level: intermediate

    2030:   Note:
    2031:   We are using a first order FEM model for the weak form\:

    2033:   $$
    2034:   \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
    2035:   $$

    2037: .seealso: `PetscDS`, `PetscBdPointFn`, `PetscDSGetBdResidual()`
    2038: @*/
    2039: PetscErrorCode PetscDSSetBdResidual(PetscDS ds, PetscInt f, PetscBdPointFn *f0, PetscBdPointFn *f1)
    2040: {
    2041:   PetscFunctionBegin;
    2043:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2044:   PetscCall(PetscWeakFormSetIndexBdResidual(ds->wf, NULL, 0, f, 0, 0, f0, 0, f1));
    2045:   PetscFunctionReturn(PETSC_SUCCESS);
    2046: }

    2048: /*@
    2049:   PetscDSHasBdJacobian - Indicates that boundary Jacobian functions have been set

    2051:   Not Collective

    2053:   Input Parameter:
    2054: . ds - The `PetscDS`

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

    2059:   Level: intermediate

    2061: .seealso: `PetscDS`, `PetscDSHasJacobian()`, `PetscDSSetBdJacobian()`, `PetscDSGetBdJacobian()`
    2062: @*/
    2063: PetscErrorCode PetscDSHasBdJacobian(PetscDS ds, PetscBool *hasBdJac)
    2064: {
    2065:   PetscFunctionBegin;
    2067:   PetscAssertPointer(hasBdJac, 2);
    2068:   PetscCall(PetscWeakFormHasBdJacobian(ds->wf, hasBdJac));
    2069:   PetscFunctionReturn(PETSC_SUCCESS);
    2070: }

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

    2075:   Not Collective

    2077:   Input Parameters:
    2078: + ds - The `PetscDS`
    2079: . f  - The test field number
    2080: - g  - The field number

    2082:   Output Parameters:
    2083: + g0 - integrand for the test and basis function term, see `PetscBdPointJacFn`
    2084: . g1 - integrand for the test function and basis function gradient term, see `PetscBdPointJacFn`
    2085: . g2 - integrand for the test function gradient and basis function term, see `PetscBdPointJacFn`
    2086: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscBdPointJacFn`

    2088:   Level: intermediate

    2090:   Note:
    2091:   We are using a first order FEM model for the weak form\:

    2093:   $$
    2094:   \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
    2095:   + \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
    2096:   $$

    2098: .seealso: `PetscDS`, `PetscBdPointJacFn`, `PetscDSSetBdJacobian()`
    2099: @*/
    2100: PetscErrorCode PetscDSGetBdJacobian(PetscDS ds, PetscInt f, PetscInt g, PetscBdPointJacFn **g0, PetscBdPointJacFn **g1, PetscBdPointJacFn **g2, PetscBdPointJacFn **g3)
    2101: {
    2102:   PetscBdPointJacFn **tmp0, **tmp1, **tmp2, **tmp3;
    2103:   PetscInt            n0, n1, n2, n3;

    2105:   PetscFunctionBegin;
    2107:   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);
    2108:   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);
    2109:   PetscCall(PetscWeakFormGetBdJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    2110:   *g0 = tmp0 ? tmp0[0] : NULL;
    2111:   *g1 = tmp1 ? tmp1[0] : NULL;
    2112:   *g2 = tmp2 ? tmp2[0] : NULL;
    2113:   *g3 = tmp3 ? tmp3[0] : NULL;
    2114:   PetscFunctionReturn(PETSC_SUCCESS);
    2115: }

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

    2120:   Not Collective

    2122:   Input Parameters:
    2123: + ds - The PetscDS
    2124: . f  - The test field number
    2125: . g  - The field number
    2126: . g0 - integrand for the test and basis function term, see `PetscBdPointJacFn`
    2127: . g1 - integrand for the test function and basis function gradient term, see `PetscBdPointJacFn`
    2128: . g2 - integrand for the test function gradient and basis function term, see `PetscBdPointJacFn`
    2129: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscBdPointJacFn`

    2131:   Level: intermediate

    2133:   Note:
    2134:   We are using a first order FEM model for the weak form\:

    2136:   $$
    2137:   \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
    2138:   + \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
    2139:   $$

    2141: .seealso: `PetscDS`, `PetscBdPointJacFn`, `PetscDSGetBdJacobian()`
    2142: @*/
    2143: PetscErrorCode PetscDSSetBdJacobian(PetscDS ds, PetscInt f, PetscInt g, PetscBdPointJacFn *g0, PetscBdPointJacFn *g1, PetscBdPointJacFn *g2, PetscBdPointJacFn *g3)
    2144: {
    2145:   PetscFunctionBegin;
    2151:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2152:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    2153:   PetscCall(PetscWeakFormSetIndexBdJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    2154:   PetscFunctionReturn(PETSC_SUCCESS);
    2155: }

    2157: /*@
    2158:   PetscDSHasBdJacobianPreconditioner - Signals that boundary Jacobian preconditioner functions have been set with `PetscDSSetBdJacobianPreconditioner()`

    2160:   Not Collective

    2162:   Input Parameter:
    2163: . ds - The `PetscDS`

    2165:   Output Parameter:
    2166: . hasBdJacPre - flag that pointwise function for the boundary Jacobian matrix to construct the preconditioner has been set

    2168:   Level: intermediate

    2170:   Developer Note:
    2171:   The name is confusing since the function computes a matrix used to construct the preconditioner, not a preconditioner.

    2173: .seealso: `PetscDS`, `PetscDSHasJacobian()`, `PetscDSSetBdJacobian()`, `PetscDSGetBdJacobian()`
    2174: @*/
    2175: PetscErrorCode PetscDSHasBdJacobianPreconditioner(PetscDS ds, PetscBool *hasBdJacPre)
    2176: {
    2177:   PetscFunctionBegin;
    2179:   PetscAssertPointer(hasBdJacPre, 2);
    2180:   PetscCall(PetscWeakFormHasBdJacobianPreconditioner(ds->wf, hasBdJacPre));
    2181:   PetscFunctionReturn(PETSC_SUCCESS);
    2182: }

    2184: /*@C
    2185:   PetscDSGetBdJacobianPreconditioner - Get the pointwise boundary Jacobian function for given test and basis field that constructs the
    2186:   matrix used to construct the preconditioner

    2188:   Not Collective; No Fortran Support

    2190:   Input Parameters:
    2191: + ds - The `PetscDS`
    2192: . f  - The test field number
    2193: - g  - The field number

    2195:   Output Parameters:
    2196: + g0 - integrand for the test and basis function term, see `PetscBdPointJacFn`
    2197: . g1 - integrand for the test function and basis function gradient term, see `PetscBdPointJacFn`
    2198: . g2 - integrand for the test function gradient and basis function term, see `PetscBdPointJacFn`
    2199: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscBdPointJacFn`

    2201:   Level: intermediate

    2203:   Note:
    2204:   We are using a first order FEM model for the weak form\:

    2206:   $$
    2207:   \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
    2208:   + \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
    2209:   $$

    2211:   Developer Note:
    2212:   The name is confusing since the function computes a matrix used to construct the preconditioner, not a preconditioner.

    2214: .seealso: `PetscDS`, `PetscBdPointJacFn`, `PetscDSSetBdJacobianPreconditioner()`
    2215: @*/
    2216: PetscErrorCode PetscDSGetBdJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g, PetscBdPointJacFn **g0, PetscBdPointJacFn **g1, PetscBdPointJacFn **g2, PetscBdPointJacFn **g3)
    2217: {
    2218:   PetscBdPointJacFn **tmp0, **tmp1, **tmp2, **tmp3;
    2219:   PetscInt            n0, n1, n2, n3;

    2221:   PetscFunctionBegin;
    2223:   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);
    2224:   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);
    2225:   PetscCall(PetscWeakFormGetBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
    2226:   *g0 = tmp0 ? tmp0[0] : NULL;
    2227:   *g1 = tmp1 ? tmp1[0] : NULL;
    2228:   *g2 = tmp2 ? tmp2[0] : NULL;
    2229:   *g3 = tmp3 ? tmp3[0] : NULL;
    2230:   PetscFunctionReturn(PETSC_SUCCESS);
    2231: }

    2233: /*@C
    2234:   PetscDSSetBdJacobianPreconditioner - Set the pointwise boundary Jacobian preconditioner function for given test and basis field that constructs the
    2235:   matrix used to construct the preconditioner

    2237:   Not Collective; No Fortran Support

    2239:   Input Parameters:
    2240: + ds - The `PetscDS`
    2241: . f  - The test field number
    2242: . g  - The field number
    2243: . g0 - integrand for the test and basis function term, see `PetscBdPointJacFn`
    2244: . g1 - integrand for the test function and basis function gradient term, see `PetscBdPointJacFn`
    2245: . g2 - integrand for the test function gradient and basis function term, see `PetscBdPointJacFn`
    2246: - g3 - integrand for the test function gradient and basis function gradient term, see `PetscBdPointJacFn`

    2248:   Level: intermediate

    2250:   Note:
    2251:   We are using a first order FEM model for the weak form\:

    2253:   $$
    2254:   \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
    2255:   + \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
    2256:   $$

    2258:   Developer Note:
    2259:   The name is confusing since the function computes a matrix used to construct the preconditioner, not a preconditioner.

    2261: .seealso: `PetscDS`, `PetscBdPointJacFn`, `PetscDSGetBdJacobianPreconditioner()`
    2262: @*/
    2263: PetscErrorCode PetscDSSetBdJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g, PetscBdPointJacFn *g0, PetscBdPointJacFn *g1, PetscBdPointJacFn *g2, PetscBdPointJacFn *g3)
    2264: {
    2265:   PetscFunctionBegin;
    2271:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2272:   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
    2273:   PetscCall(PetscWeakFormSetIndexBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
    2274:   PetscFunctionReturn(PETSC_SUCCESS);
    2275: }

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

    2280:   Not Collective

    2282:   Input Parameters:
    2283: + prob - The `PetscDS`
    2284: - f    - The test field number

    2286:   Output Parameters:
    2287: + sol - exact solution function for the test field, see `PetscPointExactSolutionFn`
    2288: - ctx - exact solution context

    2290:   Level: intermediate

    2292: .seealso: `PetscDS`, `PetscPointExactSolutionFn`, `PetscDSSetExactSolution()`, `PetscDSGetExactSolutionTimeDerivative()`
    2293: @*/
    2294: PetscErrorCode PetscDSGetExactSolution(PetscDS prob, PetscInt f, PetscPointExactSolutionFn **sol, void **ctx)
    2295: {
    2296:   PetscFunctionBegin;
    2298:   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);
    2299:   if (sol) {
    2300:     PetscAssertPointer(sol, 3);
    2301:     *sol = prob->exactSol[f];
    2302:   }
    2303:   if (ctx) {
    2304:     PetscAssertPointer(ctx, 4);
    2305:     *ctx = prob->exactCtx[f];
    2306:   }
    2307:   PetscFunctionReturn(PETSC_SUCCESS);
    2308: }

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

    2313:   Not Collective

    2315:   Input Parameters:
    2316: + prob - The `PetscDS`
    2317: . f    - The test field number
    2318: . sol  - solution function for the test fields, see `PetscPointExactSolutionFn`
    2319: - ctx  - solution context or `NULL`

    2321:   Level: intermediate

    2323: .seealso: `PetscDS`, `PetscPointExactSolutionFn`, `PetscDSGetExactSolution()`
    2324: @*/
    2325: PetscErrorCode PetscDSSetExactSolution(PetscDS prob, PetscInt f, PetscPointExactSolutionFn *sol, PetscCtx ctx)
    2326: {
    2327:   PetscFunctionBegin;
    2329:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2330:   PetscCall(PetscDSEnlarge_Static(prob, f + 1));
    2331:   if (sol) {
    2333:     prob->exactSol[f] = sol;
    2334:   }
    2335:   if (ctx) {
    2337:     prob->exactCtx[f] = ctx;
    2338:   }
    2339:   PetscFunctionReturn(PETSC_SUCCESS);
    2340: }

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

    2345:   Not Collective

    2347:   Input Parameters:
    2348: + prob - The `PetscDS`
    2349: - f    - The test field number

    2351:   Output Parameters:
    2352: + sol - time derivative of the exact solution for the test field, see `PetscPointExactSolutionFn`
    2353: - ctx - the exact solution context

    2355:   Level: intermediate

    2357: .seealso: `PetscDS`, `PetscPointExactSolutionFn`, `PetscDSSetExactSolutionTimeDerivative()`, `PetscDSGetExactSolution()`
    2358: @*/
    2359: PetscErrorCode PetscDSGetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscPointExactSolutionFn **sol, void **ctx)
    2360: {
    2361:   PetscFunctionBegin;
    2363:   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);
    2364:   if (sol) {
    2365:     PetscAssertPointer(sol, 3);
    2366:     *sol = prob->exactSol_t[f];
    2367:   }
    2368:   if (ctx) {
    2369:     PetscAssertPointer(ctx, 4);
    2370:     *ctx = prob->exactCtx_t[f];
    2371:   }
    2372:   PetscFunctionReturn(PETSC_SUCCESS);
    2373: }

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

    2378:   Not Collective

    2380:   Input Parameters:
    2381: + prob - The `PetscDS`
    2382: . f    - The test field number
    2383: . sol  - time derivative of the solution function for the test fields, see `PetscPointExactSolutionFn`
    2384: - ctx  - the solution context or `NULL`

    2386:   Level: intermediate

    2388: .seealso: `PetscDS`, `PetscPointExactSolutionFn`, `PetscDSGetExactSolutionTimeDerivative()`, `PetscDSSetExactSolution()`
    2389: @*/
    2390: PetscErrorCode PetscDSSetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscPointExactSolutionFn *sol, PetscCtx ctx)
    2391: {
    2392:   PetscFunctionBegin;
    2394:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2395:   PetscCall(PetscDSEnlarge_Static(prob, f + 1));
    2396:   if (sol) {
    2398:     prob->exactSol_t[f] = sol;
    2399:   }
    2400:   if (ctx) {
    2402:     prob->exactCtx_t[f] = ctx;
    2403:   }
    2404:   PetscFunctionReturn(PETSC_SUCCESS);
    2405: }

    2407: /*@C
    2408:   PetscDSGetLowerBound - Get the pointwise lower bound function for a given field

    2410:   Not Collective

    2412:   Input Parameters:
    2413: + ds - The PetscDS
    2414: - f  - The field number

    2416:   Output Parameters:
    2417: + lb  - lower bound function for the field, see `PetscPointBoundFn`
    2418: - ctx - lower bound context that was set with `PetscDSSetLowerBound()`

    2420:   Level: intermediate

    2422: .seealso: `PetscDS`, `PetscPointBoundFn`, `PetscDSSetLowerBound()`, `PetscDSGetUpperBound()`, `PetscDSGetExactSolution()`
    2423: @*/
    2424: PetscErrorCode PetscDSGetLowerBound(PetscDS ds, PetscInt f, PetscPointBoundFn **lb, void **ctx)
    2425: {
    2426:   PetscFunctionBegin;
    2428:   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);
    2429:   if (lb) {
    2430:     PetscAssertPointer(lb, 3);
    2431:     *lb = ds->lowerBound[f];
    2432:   }
    2433:   if (ctx) {
    2434:     PetscAssertPointer(ctx, 4);
    2435:     *ctx = ds->lowerCtx[f];
    2436:   }
    2437:   PetscFunctionReturn(PETSC_SUCCESS);
    2438: }

    2440: /*@C
    2441:   PetscDSSetLowerBound - Set the pointwise lower bound function for a given field

    2443:   Not Collective

    2445:   Input Parameters:
    2446: + ds  - The `PetscDS`
    2447: . f   - The field number
    2448: . lb  - lower bound function for the test fields, see `PetscPointBoundFn`
    2449: - ctx - lower bound context or `NULL` which will be passed to `lb`

    2451:   Level: intermediate

    2453: .seealso: `PetscDS`, `PetscPointBoundFn`, `PetscDSGetLowerBound()`, `PetscDSGetUpperBound()`, `PetscDSGetExactSolution()`
    2454: @*/
    2455: PetscErrorCode PetscDSSetLowerBound(PetscDS ds, PetscInt f, PetscPointBoundFn *lb, PetscCtx ctx)
    2456: {
    2457:   PetscFunctionBegin;
    2459:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2460:   PetscCall(PetscDSEnlarge_Static(ds, f + 1));
    2461:   if (lb) {
    2463:     ds->lowerBound[f] = lb;
    2464:   }
    2465:   if (ctx) {
    2467:     ds->lowerCtx[f] = ctx;
    2468:   }
    2469:   PetscFunctionReturn(PETSC_SUCCESS);
    2470: }

    2472: /*@C
    2473:   PetscDSGetUpperBound - Get the pointwise upper bound function for a given field

    2475:   Not Collective

    2477:   Input Parameters:
    2478: + ds - The `PetscDS`
    2479: - f  - The field number

    2481:   Output Parameters:
    2482: + ub  - upper bound function for the field, see `PetscPointBoundFn`
    2483: - ctx - upper bound context that was set with `PetscDSSetUpperBound()`

    2485:   Level: intermediate

    2487: .seealso: `PetscDS`, `PetscPointBoundFn`, `PetscDSSetUpperBound()`, `PetscDSGetLowerBound()`, `PetscDSGetExactSolution()`
    2488: @*/
    2489: PetscErrorCode PetscDSGetUpperBound(PetscDS ds, PetscInt f, PetscPointBoundFn **ub, void **ctx)
    2490: {
    2491:   PetscFunctionBegin;
    2493:   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);
    2494:   if (ub) {
    2495:     PetscAssertPointer(ub, 3);
    2496:     *ub = ds->upperBound[f];
    2497:   }
    2498:   if (ctx) {
    2499:     PetscAssertPointer(ctx, 4);
    2500:     *ctx = ds->upperCtx[f];
    2501:   }
    2502:   PetscFunctionReturn(PETSC_SUCCESS);
    2503: }

    2505: /*@C
    2506:   PetscDSSetUpperBound - Set the pointwise upper bound function for a given field

    2508:   Not Collective

    2510:   Input Parameters:
    2511: + ds  - The `PetscDS`
    2512: . f   - The field number
    2513: . ub  - upper bound function for the test fields, see `PetscPointBoundFn`
    2514: - ctx - context or `NULL` that will be passed to `ub`

    2516:   Level: intermediate

    2518: .seealso: `PetscDS`, `PetscPointBoundFn`, `PetscDSGetUpperBound()`, `PetscDSGetLowerBound()`, `PetscDSGetExactSolution()`
    2519: @*/
    2520: PetscErrorCode PetscDSSetUpperBound(PetscDS ds, PetscInt f, PetscPointBoundFn *ub, PetscCtx ctx)
    2521: {
    2522:   PetscFunctionBegin;
    2524:   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
    2525:   PetscCall(PetscDSEnlarge_Static(ds, f + 1));
    2526:   if (ub) {
    2528:     ds->upperBound[f] = ub;
    2529:   }
    2530:   if (ctx) {
    2532:     ds->upperCtx[f] = ctx;
    2533:   }
    2534:   PetscFunctionReturn(PETSC_SUCCESS);
    2535: }

    2537: /*@C
    2538:   PetscDSGetConstants - Returns the array of constants passed to point functions from a `PetscDS` object

    2540:   Not Collective

    2542:   Input Parameter:
    2543: . ds - The `PetscDS` object

    2545:   Output Parameters:
    2546: + numConstants - The number of constants, or pass in `NULL` if not required
    2547: - constants    - The array of constants, `NULL` if there are none

    2549:   Level: intermediate

    2551: .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSCreate()`
    2552: @*/
    2553: PetscErrorCode PetscDSGetConstants(PetscDS ds, PeOp PetscInt *numConstants, PeOp const PetscScalar *constants[])
    2554: {
    2555:   PetscFunctionBegin;
    2557:   if (numConstants) {
    2558:     PetscAssertPointer(numConstants, 2);
    2559:     *numConstants = ds->numConstants;
    2560:   }
    2561:   if (constants) {
    2562:     PetscAssertPointer(constants, 3);
    2563:     *constants = ds->constants;
    2564:   }
    2565:   PetscFunctionReturn(PETSC_SUCCESS);
    2566: }

    2568: /*@C
    2569:   PetscDSSetConstants - Set the array of constants passed to point functions from a `PetscDS`

    2571:   Not Collective

    2573:   Input Parameters:
    2574: + ds           - The `PetscDS` object
    2575: . numConstants - The number of constants
    2576: - constants    - The array of constants, `NULL` if there are none

    2578:   Level: intermediate

    2580: .seealso: `PetscDS`, `PetscDSGetConstants()`, `PetscDSCreate()`
    2581: @*/
    2582: PetscErrorCode PetscDSSetConstants(PetscDS ds, PetscInt numConstants, PetscScalar constants[])
    2583: {
    2584:   PetscFunctionBegin;
    2586:   if (numConstants != ds->numConstants) {
    2587:     PetscCall(PetscFree(ds->constants));
    2588:     ds->numConstants = numConstants;
    2589:     PetscCall(PetscMalloc1(ds->numConstants + ds->numFuncConstants, &ds->constants));
    2590:   }
    2591:   if (ds->numConstants) {
    2592:     PetscAssertPointer(constants, 3);
    2593:     PetscCall(PetscArraycpy(ds->constants, constants, ds->numConstants));
    2594:   }
    2595:   PetscFunctionReturn(PETSC_SUCCESS);
    2596: }

    2598: /*@C
    2599:   PetscDSSetIntegrationParameters - Set the parameters for a particular integration

    2601:   Not Collective

    2603:   Input Parameters:
    2604: + ds     - The `PetscDS` object
    2605: . fieldI - The test field for a given point function, or `PETSC_DETERMINE`
    2606: - fieldJ - The basis field for a given point function, or `PETSC_DETERMINE`

    2608:   Level: intermediate

    2610: .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSGetConstants()`, `PetscDSCreate()`
    2611: @*/
    2612: PetscErrorCode PetscDSSetIntegrationParameters(PetscDS ds, PetscInt fieldI, PetscInt fieldJ)
    2613: {
    2614:   PetscFunctionBegin;
    2616:   ds->constants[ds->numConstants]     = fieldI;
    2617:   ds->constants[ds->numConstants + 1] = fieldJ;
    2618:   PetscFunctionReturn(PETSC_SUCCESS);
    2619: }

    2621: /*@C
    2622:   PetscDSSetCellParameters - Set the parameters for a particular cell

    2624:   Not Collective

    2626:   Input Parameters:
    2627: + ds     - The `PetscDS` object
    2628: - volume - The cell volume

    2630:   Level: intermediate

    2632: .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSGetConstants()`, `PetscDSCreate()`
    2633: @*/
    2634: PetscErrorCode PetscDSSetCellParameters(PetscDS ds, PetscReal volume)
    2635: {
    2636:   PetscFunctionBegin;
    2638:   ds->constants[ds->numConstants + 2] = volume;
    2639:   PetscFunctionReturn(PETSC_SUCCESS);
    2640: }

    2642: /*@
    2643:   PetscDSGetFieldIndex - Returns the index of the given field

    2645:   Not Collective

    2647:   Input Parameters:
    2648: + prob - The `PetscDS` object
    2649: - disc - The discretization object

    2651:   Output Parameter:
    2652: . f - The field number

    2654:   Level: beginner

    2656: .seealso: `PetscDS`, `PetscGetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2657: @*/
    2658: PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
    2659: {
    2660:   PetscInt g;

    2662:   PetscFunctionBegin;
    2664:   PetscAssertPointer(f, 3);
    2665:   *f = -1;
    2666:   for (g = 0; g < prob->Nf; ++g) {
    2667:     if (disc == prob->disc[g]) break;
    2668:   }
    2669:   PetscCheck(g != prob->Nf, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
    2670:   *f = g;
    2671:   PetscFunctionReturn(PETSC_SUCCESS);
    2672: }

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

    2677:   Not Collective

    2679:   Input Parameters:
    2680: + prob - The `PetscDS` object
    2681: - f    - The field number

    2683:   Output Parameter:
    2684: . size - The size

    2686:   Level: beginner

    2688: .seealso: `PetscDS`, `PetscDSGetFieldOffset()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2689: @*/
    2690: PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
    2691: {
    2692:   PetscFunctionBegin;
    2694:   PetscAssertPointer(size, 3);
    2695:   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);
    2696:   PetscCall(PetscDSSetUp(prob));
    2697:   *size = prob->Nb[f];
    2698:   PetscFunctionReturn(PETSC_SUCCESS);
    2699: }

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

    2704:   Not Collective

    2706:   Input Parameters:
    2707: + prob - The `PetscDS` object
    2708: - f    - The field number

    2710:   Output Parameter:
    2711: . off - The offset

    2713:   Level: beginner

    2715: .seealso: `PetscDS`, `PetscDSGetFieldSize()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2716: @*/
    2717: PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
    2718: {
    2719:   PetscInt size, g;

    2721:   PetscFunctionBegin;
    2723:   PetscAssertPointer(off, 3);
    2724:   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);
    2725:   *off = 0;
    2726:   for (g = 0; g < f; ++g) {
    2727:     PetscCall(PetscDSGetFieldSize(prob, g, &size));
    2728:     *off += size;
    2729:   }
    2730:   PetscFunctionReturn(PETSC_SUCCESS);
    2731: }

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

    2736:   Not Collective

    2738:   Input Parameters:
    2739: + ds - The `PetscDS` object
    2740: - f  - The field number

    2742:   Output Parameter:
    2743: . off - The offset

    2745:   Level: beginner

    2747: .seealso: `PetscDS`, `PetscDSGetFieldSize()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2748: @*/
    2749: PetscErrorCode PetscDSGetFieldOffsetCohesive(PetscDS ds, PetscInt f, PetscInt *off)
    2750: {
    2751:   PetscInt size, g;

    2753:   PetscFunctionBegin;
    2755:   PetscAssertPointer(off, 3);
    2756:   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);
    2757:   *off = 0;
    2758:   for (g = 0; g < f; ++g) {
    2759:     PetscBool cohesive;

    2761:     PetscCall(PetscDSGetCohesive(ds, g, &cohesive));
    2762:     PetscCall(PetscDSGetFieldSize(ds, g, &size));
    2763:     *off += cohesive ? size : size * 2;
    2764:   }
    2765:   PetscFunctionReturn(PETSC_SUCCESS);
    2766: }

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

    2771:   Not Collective

    2773:   Input Parameter:
    2774: . prob - The `PetscDS` object

    2776:   Output Parameter:
    2777: . dimensions - The number of dimensions

    2779:   Level: beginner

    2781: .seealso: `PetscDS`, `PetscDSGetComponentOffsets()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2782: @*/
    2783: PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
    2784: {
    2785:   PetscFunctionBegin;
    2787:   PetscCall(PetscDSSetUp(prob));
    2788:   PetscAssertPointer(dimensions, 2);
    2789:   *dimensions = prob->Nb;
    2790:   PetscFunctionReturn(PETSC_SUCCESS);
    2791: }

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

    2796:   Not Collective

    2798:   Input Parameter:
    2799: . prob - The `PetscDS` object

    2801:   Output Parameter:
    2802: . components - The number of components

    2804:   Level: beginner

    2806: .seealso: `PetscDS`, `PetscDSGetComponentOffsets()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2807: @*/
    2808: PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
    2809: {
    2810:   PetscFunctionBegin;
    2812:   PetscCall(PetscDSSetUp(prob));
    2813:   PetscAssertPointer(components, 2);
    2814:   *components = prob->Nc;
    2815:   PetscFunctionReturn(PETSC_SUCCESS);
    2816: }

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

    2821:   Not Collective

    2823:   Input Parameters:
    2824: + prob - The `PetscDS` object
    2825: - f    - The field number

    2827:   Output Parameter:
    2828: . off - The offset

    2830:   Level: beginner

    2832: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2833: @*/
    2834: PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
    2835: {
    2836:   PetscFunctionBegin;
    2838:   PetscAssertPointer(off, 3);
    2839:   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);
    2840:   PetscCall(PetscDSSetUp(prob));
    2841:   *off = prob->off[f];
    2842:   PetscFunctionReturn(PETSC_SUCCESS);
    2843: }

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

    2848:   Not Collective

    2850:   Input Parameter:
    2851: . prob - The `PetscDS` object

    2853:   Output Parameter:
    2854: . offsets - The offsets

    2856:   Level: beginner

    2858: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2859: @*/
    2860: PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
    2861: {
    2862:   PetscFunctionBegin;
    2864:   PetscAssertPointer(offsets, 2);
    2865:   PetscCall(PetscDSSetUp(prob));
    2866:   *offsets = prob->off;
    2867:   PetscFunctionReturn(PETSC_SUCCESS);
    2868: }

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

    2873:   Not Collective

    2875:   Input Parameter:
    2876: . prob - The `PetscDS` object

    2878:   Output Parameter:
    2879: . offsets - The offsets

    2881:   Level: beginner

    2883: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2884: @*/
    2885: PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
    2886: {
    2887:   PetscFunctionBegin;
    2889:   PetscAssertPointer(offsets, 2);
    2890:   PetscCall(PetscDSSetUp(prob));
    2891:   *offsets = prob->offDer;
    2892:   PetscFunctionReturn(PETSC_SUCCESS);
    2893: }

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

    2898:   Not Collective

    2900:   Input Parameters:
    2901: + ds - The `PetscDS` object
    2902: - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive

    2904:   Output Parameter:
    2905: . offsets - The offsets

    2907:   Level: beginner

    2909: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2910: @*/
    2911: PetscErrorCode PetscDSGetComponentOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
    2912: {
    2913:   PetscFunctionBegin;
    2915:   PetscAssertPointer(offsets, 3);
    2916:   PetscCheck(ds->isCohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
    2917:   PetscCheck(!(s < 0) && !(s > 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %" PetscInt_FMT " is not in [0, 2]", s);
    2918:   PetscCall(PetscDSSetUp(ds));
    2919:   *offsets = ds->offCohesive[s];
    2920:   PetscFunctionReturn(PETSC_SUCCESS);
    2921: }

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

    2926:   Not Collective

    2928:   Input Parameters:
    2929: + ds - The `PetscDS` object
    2930: - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive

    2932:   Output Parameter:
    2933: . offsets - The offsets

    2935:   Level: beginner

    2937: .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
    2938: @*/
    2939: PetscErrorCode PetscDSGetComponentDerivativeOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
    2940: {
    2941:   PetscFunctionBegin;
    2943:   PetscAssertPointer(offsets, 3);
    2944:   PetscCheck(ds->isCohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
    2945:   PetscCheck(!(s < 0) && !(s > 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %" PetscInt_FMT " is not in [0, 2]", s);
    2946:   PetscCall(PetscDSSetUp(ds));
    2947:   *offsets = ds->offDerCohesive[s];
    2948:   PetscFunctionReturn(PETSC_SUCCESS);
    2949: }

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

    2954:   Not Collective

    2956:   Input Parameter:
    2957: . prob - The `PetscDS` object

    2959:   Output Parameter:
    2960: . T - The basis function and derivatives tabulation at quadrature points for each field, see `PetscTabulation` for its details

    2962:   Level: intermediate

    2964:   Note:
    2965:   The tabulation is only valid so long as the `PetscDS` has not be destroyed. There is no `PetscDSRestoreTabulation()` in C.

    2967:   Fortran Note:
    2968:   Use the declaration
    2969: .vb
    2970:   PetscTabulation, pointer :: tab(:)
    2971: .ve
    2972:   and access the values using, for example,
    2973: .vb
    2974:   tab(i)%ptr%K
    2975:   tab(i)%ptr%T(j)%ptr
    2976: .ve
    2977:   where $ i = 1, 2, ..., Nf $ and $ j = 1, 2, ..., tab(i)%ptr%K+1 $.

    2979:   Use `PetscDSRestoreTabulation()` to restore the array

    2981:   Developer Note:
    2982:   The Fortran language syntax does not directly support arrays of pointers, the '%ptr' notation allows mimicking their use in Fortran.

    2984: .seealso: `PetscDS`, `PetscTabulation`, `PetscDSCreate()`
    2985: @*/
    2986: PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[]) PeNS
    2987: {
    2988:   PetscFunctionBegin;
    2990:   PetscAssertPointer(T, 2);
    2991:   PetscCall(PetscDSSetUp(prob));
    2992:   *T = prob->T;
    2993:   PetscFunctionReturn(PETSC_SUCCESS);
    2994: }

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

    2999:   Not Collective

    3001:   Input Parameter:
    3002: . prob - The `PetscDS` object

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

    3007:   Level: intermediate

    3009:   Note:
    3010:   The tabulation is only valid so long as the `PetscDS` has not be destroyed. There is no `PetscDSRestoreFaceTabulation()` in C.

    3012: .seealso: `PetscTabulation`, `PetscDS`, `PetscDSGetTabulation()`, `PetscDSCreate()`
    3013: @*/
    3014: PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
    3015: {
    3016:   PetscFunctionBegin;
    3018:   PetscAssertPointer(Tf, 2);
    3019:   PetscCall(PetscDSSetUp(prob));
    3020:   *Tf = prob->Tf;
    3021:   PetscFunctionReturn(PETSC_SUCCESS);
    3022: }

    3024: PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar *u[], PetscScalar *u_t[], PetscScalar *u_x[])
    3025: {
    3026:   PetscFunctionBegin;
    3028:   PetscCall(PetscDSSetUp(prob));
    3029:   if (u) {
    3030:     PetscAssertPointer(u, 2);
    3031:     *u = prob->u;
    3032:   }
    3033:   if (u_t) {
    3034:     PetscAssertPointer(u_t, 3);
    3035:     *u_t = prob->u_t;
    3036:   }
    3037:   if (u_x) {
    3038:     PetscAssertPointer(u_x, 4);
    3039:     *u_x = prob->u_x;
    3040:   }
    3041:   PetscFunctionReturn(PETSC_SUCCESS);
    3042: }

    3044: PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar *f0[], PetscScalar *f1[], PetscScalar *g0[], PetscScalar *g1[], PetscScalar *g2[], PetscScalar *g3[])
    3045: {
    3046:   PetscFunctionBegin;
    3048:   PetscCall(PetscDSSetUp(prob));
    3049:   if (f0) {
    3050:     PetscAssertPointer(f0, 2);
    3051:     *f0 = prob->f0;
    3052:   }
    3053:   if (f1) {
    3054:     PetscAssertPointer(f1, 3);
    3055:     *f1 = prob->f1;
    3056:   }
    3057:   if (g0) {
    3058:     PetscAssertPointer(g0, 4);
    3059:     *g0 = prob->g0;
    3060:   }
    3061:   if (g1) {
    3062:     PetscAssertPointer(g1, 5);
    3063:     *g1 = prob->g1;
    3064:   }
    3065:   if (g2) {
    3066:     PetscAssertPointer(g2, 6);
    3067:     *g2 = prob->g2;
    3068:   }
    3069:   if (g3) {
    3070:     PetscAssertPointer(g3, 7);
    3071:     *g3 = prob->g3;
    3072:   }
    3073:   PetscFunctionReturn(PETSC_SUCCESS);
    3074: }

    3076: PetscErrorCode PetscDSGetWorkspace(PetscDS prob, PetscReal **x, PetscScalar **basisReal, PetscScalar **basisDerReal, PetscScalar **testReal, PetscScalar **testDerReal)
    3077: {
    3078:   PetscFunctionBegin;
    3080:   PetscCall(PetscDSSetUp(prob));
    3081:   if (x) {
    3082:     PetscAssertPointer(x, 2);
    3083:     *x = prob->x;
    3084:   }
    3085:   if (basisReal) {
    3086:     PetscAssertPointer(basisReal, 3);
    3087:     *basisReal = prob->basisReal;
    3088:   }
    3089:   if (basisDerReal) {
    3090:     PetscAssertPointer(basisDerReal, 4);
    3091:     *basisDerReal = prob->basisDerReal;
    3092:   }
    3093:   if (testReal) {
    3094:     PetscAssertPointer(testReal, 5);
    3095:     *testReal = prob->testReal;
    3096:   }
    3097:   if (testDerReal) {
    3098:     PetscAssertPointer(testDerReal, 6);
    3099:     *testDerReal = prob->testDerReal;
    3100:   }
    3101:   PetscFunctionReturn(PETSC_SUCCESS);
    3102: }

    3104: /*@C
    3105:   PetscDSAddBoundary - Add a boundary condition to the model.

    3107:   Collective

    3109:   Input Parameters:
    3110: + ds       - The `PetscDS` object
    3111: . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
    3112: . name     - The name for the boundary condition
    3113: . label    - The label defining constrained points
    3114: . Nv       - The number of `DMLabel` values for constrained points
    3115: . values   - An array of label values for constrained points
    3116: . field    - The field to constrain
    3117: . Nc       - The number of constrained field components (0 will constrain all fields)
    3118: . comps    - An array of constrained component numbers
    3119: . bcFunc   - A pointwise function giving boundary values
    3120: . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or `NULL`
    3121: - ctx      - An optional user context for `bcFunc`

    3123:   Output Parameter:
    3124: . bd - The boundary number

    3126:   Options Database Keys:
    3127: + -bc_NAME values     - comma separated list of values for the boundary condition NAME
    3128: - -bc_NAME_comp comps - comma separated list of components for the boundary condition NAME

    3130:   Level: developer

    3132:   Note:
    3133:   Both `bcFunc` and `bcFunc_t` will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
    3134: .vb
    3135:   void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
    3136: .ve

    3138:   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
    3139: .vb
    3140:   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    3141:               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    3142:               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    3143:               PetscReal time, const PetscReal x[], PetscScalar bcval[])
    3144: .ve
    3145: + dim          - the coordinate dimension
    3146: . Nf           - the number of fields
    3147: . uOff         - the offset into u[] and u_t[] for each field
    3148: . uOff_x       - the offset into u_x[] for each field
    3149: . u            - each field evaluated at the current point
    3150: . u_t          - the time derivative of each field evaluated at the current point
    3151: . u_x          - the gradient of each field evaluated at the current point
    3152: . aOff         - the offset into a[] and a_t[] for each auxiliary field
    3153: . aOff_x       - the offset into a_x[] for each auxiliary field
    3154: . a            - each auxiliary field evaluated at the current point
    3155: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    3156: . a_x          - the gradient of auxiliary each field evaluated at the current point
    3157: . t            - current time
    3158: . x            - coordinates of the current point
    3159: . numConstants - number of constant parameters
    3160: . constants    - constant parameters
    3161: - bcval        - output values at the current point

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

    3169: .seealso: `PetscDS`, `PetscWeakForm`, `DMLabel`, `DMBoundaryConditionType`, `PetscDSAddBoundaryByName()`, `PetscDSGetBoundary()`, `PetscDSSetResidual()`, `PetscDSSetBdResidual()`
    3170: @*/
    3171: PetscErrorCode PetscDSAddBoundary(PetscDS ds, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], PetscVoidFn *bcFunc, PetscVoidFn *bcFunc_t, PetscCtx ctx, PetscInt *bd)
    3172: {
    3173:   DSBoundary  head = ds->boundary, b;
    3174:   PetscInt    n    = 0;
    3175:   const char *lname;

    3177:   PetscFunctionBegin;
    3180:   PetscAssertPointer(name, 3);
    3185:   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);
    3186:   if (Nc > 0) {
    3187:     PetscInt *fcomps;
    3188:     PetscInt  c;

    3190:     PetscCall(PetscDSGetComponents(ds, &fcomps));
    3191:     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);
    3192:     for (c = 0; c < Nc; ++c) {
    3193:       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);
    3194:     }
    3195:   }
    3196:   PetscCall(PetscNew(&b));
    3197:   PetscCall(PetscStrallocpy(name, (char **)&b->name));
    3198:   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
    3199:   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
    3200:   PetscCall(PetscMalloc1(Nv, &b->values));
    3201:   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
    3202:   PetscCall(PetscMalloc1(Nc, &b->comps));
    3203:   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
    3204:   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
    3205:   PetscCall(PetscStrallocpy(lname, (char **)&b->lname));
    3206:   b->type   = type;
    3207:   b->label  = label;
    3208:   b->Nv     = Nv;
    3209:   b->field  = field;
    3210:   b->Nc     = Nc;
    3211:   b->func   = bcFunc;
    3212:   b->func_t = bcFunc_t;
    3213:   b->ctx    = ctx;
    3214:   b->next   = NULL;
    3215:   /* Append to linked list so that we can preserve the order */
    3216:   if (!head) ds->boundary = b;
    3217:   while (head) {
    3218:     if (!head->next) {
    3219:       head->next = b;
    3220:       head       = b;
    3221:     }
    3222:     head = head->next;
    3223:     ++n;
    3224:   }
    3225:   if (bd) {
    3226:     PetscAssertPointer(bd, 13);
    3227:     *bd = n;
    3228:   }
    3229:   PetscFunctionReturn(PETSC_SUCCESS);
    3230: }

    3232: // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
    3233: /*@C
    3234:   PetscDSAddBoundaryByName - Add a boundary condition to the model.

    3236:   Collective

    3238:   Input Parameters:
    3239: + ds       - The `PetscDS` object
    3240: . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
    3241: . name     - The boundary condition name
    3242: . lname    - The name of the label defining constrained points
    3243: . Nv       - The number of `DMLabel` values for constrained points
    3244: . values   - An array of label values for constrained points
    3245: . field    - The field to constrain
    3246: . Nc       - The number of constrained field components (0 will constrain all fields)
    3247: . comps    - An array of constrained component numbers
    3248: . bcFunc   - A pointwise function giving boundary values
    3249: . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or `NULL`
    3250: - ctx      - An optional user context for `bcFunc`

    3252:   Output Parameter:
    3253: . bd - The boundary number

    3255:   Options Database Keys:
    3256: + -bc_NAME values     - comma separated list of values for the boundary condition NAME
    3257: - -bc_NAME_comp comps - comma separated list of components for the boundary condition NAME

    3259:   Calling Sequence of `bcFunc` and `bcFunc_t`:
    3260:   If the type is `DM_BC_ESSENTIAL`
    3261: .vb
    3262:   void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
    3263: .ve
    3264:   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value,
    3265: .vb
    3266:   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    3267:               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    3268:               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    3269:               PetscReal time, const PetscReal x[], PetscScalar bcval[])
    3270: .ve
    3271: + dim          - the coordinate dimension
    3272: . Nf           - the number of fields
    3273: . uOff         - the offset into `u`[] and `u_t`[] for each field
    3274: . uOff_x       - the offset into `u_x`[] for each field
    3275: . u            - each field evaluated at the current point
    3276: . u_t          - the time derivative of each field evaluated at the current point
    3277: . u_x          - the gradient of each field evaluated at the current point
    3278: . aOff         - the offset into `a`[] and `a_t`[] for each auxiliary field
    3279: . aOff_x       - the offset into `a_x`[] for each auxiliary field
    3280: . a            - each auxiliary field evaluated at the current point
    3281: . a_t          - the time derivative of each auxiliary field evaluated at the current point
    3282: . a_x          - the gradient of auxiliary each field evaluated at the current point
    3283: . t            - current time
    3284: . x            - coordinates of the current point
    3285: . numConstants - number of constant parameters
    3286: . constants    - constant parameters
    3287: - bcval        - output values at the current point

    3289:   Level: developer

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

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

    3299: .seealso: `PetscDS`, `PetscWeakForm`, `DMLabel`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`, `PetscDSSetResidual()`, `PetscDSSetBdResidual()`
    3300: @*/
    3301: PetscErrorCode PetscDSAddBoundaryByName(PetscDS ds, DMBoundaryConditionType type, const char name[], const char lname[], PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], PetscVoidFn *bcFunc, PetscVoidFn *bcFunc_t, PetscCtx ctx, PetscInt *bd)
    3302: {
    3303:   DSBoundary head = ds->boundary, b;
    3304:   PetscInt   n    = 0;

    3306:   PetscFunctionBegin;
    3309:   PetscAssertPointer(name, 3);
    3310:   PetscAssertPointer(lname, 4);
    3314:   PetscCall(PetscNew(&b));
    3315:   PetscCall(PetscStrallocpy(name, (char **)&b->name));
    3316:   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
    3317:   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
    3318:   PetscCall(PetscMalloc1(Nv, &b->values));
    3319:   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
    3320:   PetscCall(PetscMalloc1(Nc, &b->comps));
    3321:   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
    3322:   PetscCall(PetscStrallocpy(lname, (char **)&b->lname));
    3323:   b->type   = type;
    3324:   b->label  = NULL;
    3325:   b->Nv     = Nv;
    3326:   b->field  = field;
    3327:   b->Nc     = Nc;
    3328:   b->func   = bcFunc;
    3329:   b->func_t = bcFunc_t;
    3330:   b->ctx    = ctx;
    3331:   b->next   = NULL;
    3332:   /* Append to linked list so that we can preserve the order */
    3333:   if (!head) ds->boundary = b;
    3334:   while (head) {
    3335:     if (!head->next) {
    3336:       head->next = b;
    3337:       head       = b;
    3338:     }
    3339:     head = head->next;
    3340:     ++n;
    3341:   }
    3342:   if (bd) {
    3343:     PetscAssertPointer(bd, 13);
    3344:     *bd = n;
    3345:   }
    3346:   PetscFunctionReturn(PETSC_SUCCESS);
    3347: }

    3349: /*@C
    3350:   PetscDSUpdateBoundary - Change a boundary condition for the model.

    3352:   Input Parameters:
    3353: + ds       - The `PetscDS` object
    3354: . bd       - The boundary condition number
    3355: . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
    3356: . name     - The boundary condition name
    3357: . label    - The label defining constrained points
    3358: . Nv       - The number of `DMLabel` ids for constrained points
    3359: . values   - An array of ids for constrained points
    3360: . field    - The field to constrain
    3361: . Nc       - The number of constrained field components
    3362: . comps    - An array of constrained component numbers
    3363: . bcFunc   - A pointwise function giving boundary values
    3364: . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or `NULL`
    3365: - ctx      - An optional user context for `bcFunc`

    3367:   Level: developer

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

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

    3378: .seealso: `PetscDS`, `PetscWeakForm`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`, `PetscDSGetNumBoundary()`, `DMLabel`
    3379: @*/
    3380: 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[], PetscVoidFn *bcFunc, PetscVoidFn *bcFunc_t, PetscCtx ctx)
    3381: {
    3382:   DSBoundary b = ds->boundary;
    3383:   PetscInt   n = 0;

    3385:   PetscFunctionBegin;
    3387:   while (b) {
    3388:     if (n == bd) break;
    3389:     b = b->next;
    3390:     ++n;
    3391:   }
    3392:   PetscCheck(b, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bd, n);
    3393:   if (name) {
    3394:     PetscCall(PetscFree(b->name));
    3395:     PetscCall(PetscStrallocpy(name, (char **)&b->name));
    3396:   }
    3397:   b->type = type;
    3398:   if (label) {
    3399:     const char *name;

    3401:     b->label = label;
    3402:     PetscCall(PetscFree(b->lname));
    3403:     PetscCall(PetscObjectGetName((PetscObject)label, &name));
    3404:     PetscCall(PetscStrallocpy(name, (char **)&b->lname));
    3405:   }
    3406:   if (Nv >= 0) {
    3407:     b->Nv = Nv;
    3408:     PetscCall(PetscFree(b->values));
    3409:     PetscCall(PetscMalloc1(Nv, &b->values));
    3410:     if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
    3411:   }
    3412:   if (field >= 0) b->field = field;
    3413:   if (Nc >= 0) {
    3414:     b->Nc = Nc;
    3415:     PetscCall(PetscFree(b->comps));
    3416:     PetscCall(PetscMalloc1(Nc, &b->comps));
    3417:     if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
    3418:   }
    3419:   if (bcFunc) b->func = bcFunc;
    3420:   if (bcFunc_t) b->func_t = bcFunc_t;
    3421:   if (ctx) b->ctx = ctx;
    3422:   PetscFunctionReturn(PETSC_SUCCESS);
    3423: }

    3425: /*@
    3426:   PetscDSGetNumBoundary - Get the number of registered boundary conditions

    3428:   Input Parameter:
    3429: . ds - The `PetscDS` object

    3431:   Output Parameter:
    3432: . numBd - The number of boundary conditions

    3434:   Level: intermediate

    3436: .seealso: `PetscDS`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`
    3437: @*/
    3438: PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
    3439: {
    3440:   DSBoundary b = ds->boundary;

    3442:   PetscFunctionBegin;
    3444:   PetscAssertPointer(numBd, 2);
    3445:   *numBd = 0;
    3446:   while (b) {
    3447:     ++(*numBd);
    3448:     b = b->next;
    3449:   }
    3450:   PetscFunctionReturn(PETSC_SUCCESS);
    3451: }

    3453: /*@C
    3454:   PetscDSGetBoundary - Gets a boundary condition from the model

    3456:   Input Parameters:
    3457: + ds - The `PetscDS` object
    3458: - bd - The boundary condition number

    3460:   Output Parameters:
    3461: + wf     - The `PetscWeakForm` holding the pointwise functions
    3462: . type   - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
    3463: . name   - The boundary condition name
    3464: . label  - The label defining constrained points
    3465: . Nv     - The number of `DMLabel` ids for constrained points
    3466: . values - An array of ids for constrained points
    3467: . field  - The field to constrain
    3468: . Nc     - The number of constrained field components
    3469: . comps  - An array of constrained component numbers
    3470: . func   - A pointwise function giving boundary values
    3471: . func_t - A pointwise function giving the time derivative of the boundary values
    3472: - ctx    - An optional user context for `bcFunc`

    3474:   Level: developer

    3476: .seealso: `PetscDS`, `PetscWeakForm`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `DMLabel`
    3477: @*/
    3478: 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[], PetscVoidFn **func, PetscVoidFn **func_t, void **ctx)
    3479: {
    3480:   DSBoundary b = ds->boundary;
    3481:   PetscInt   n = 0;

    3483:   PetscFunctionBegin;
    3485:   while (b) {
    3486:     if (n == bd) break;
    3487:     b = b->next;
    3488:     ++n;
    3489:   }
    3490:   PetscCheck(b, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bd, n);
    3491:   if (wf) {
    3492:     PetscAssertPointer(wf, 3);
    3493:     *wf = b->wf;
    3494:   }
    3495:   if (type) {
    3496:     PetscAssertPointer(type, 4);
    3497:     *type = b->type;
    3498:   }
    3499:   if (name) {
    3500:     PetscAssertPointer(name, 5);
    3501:     *name = b->name;
    3502:   }
    3503:   if (label) {
    3504:     PetscAssertPointer(label, 6);
    3505:     *label = b->label;
    3506:   }
    3507:   if (Nv) {
    3508:     PetscAssertPointer(Nv, 7);
    3509:     *Nv = b->Nv;
    3510:   }
    3511:   if (values) {
    3512:     PetscAssertPointer(values, 8);
    3513:     *values = b->values;
    3514:   }
    3515:   if (field) {
    3516:     PetscAssertPointer(field, 9);
    3517:     *field = b->field;
    3518:   }
    3519:   if (Nc) {
    3520:     PetscAssertPointer(Nc, 10);
    3521:     *Nc = b->Nc;
    3522:   }
    3523:   if (comps) {
    3524:     PetscAssertPointer(comps, 11);
    3525:     *comps = b->comps;
    3526:   }
    3527:   if (func) {
    3528:     PetscAssertPointer(func, 12);
    3529:     *func = b->func;
    3530:   }
    3531:   if (func_t) {
    3532:     PetscAssertPointer(func_t, 13);
    3533:     *func_t = b->func_t;
    3534:   }
    3535:   if (ctx) {
    3536:     PetscAssertPointer(ctx, 14);
    3537:     *ctx = b->ctx;
    3538:   }
    3539:   PetscFunctionReturn(PETSC_SUCCESS);
    3540: }

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

    3545:   Not Collective

    3547:   Input Parameters:
    3548: + ds - The source `PetscDS` object
    3549: - dm - The `DM` holding labels

    3551:   Level: intermediate

    3553: .seealso: `PetscDS`, `DMBoundary`, `DM`, `PetscDSCopyBoundary()`, `PetscDSCreate()`, `DMGetLabel()`
    3554: @*/
    3555: PetscErrorCode PetscDSUpdateBoundaryLabels(PetscDS ds, DM dm)
    3556: {
    3557:   DSBoundary b;

    3559:   PetscFunctionBegin;
    3562:   for (b = ds->boundary; b; b = b->next) {
    3563:     if (b->lname) PetscCall(DMGetLabel(dm, b->lname, &b->label));
    3564:   }
    3565:   PetscFunctionReturn(PETSC_SUCCESS);
    3566: }

    3568: static PetscErrorCode DSBoundaryDuplicate_Internal(DSBoundary b, DSBoundary *bNew)
    3569: {
    3570:   PetscFunctionBegin;
    3571:   PetscCall(PetscNew(bNew));
    3572:   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &(*bNew)->wf));
    3573:   PetscCall(PetscWeakFormCopy(b->wf, (*bNew)->wf));
    3574:   PetscCall(PetscStrallocpy(b->name, (char **)&((*bNew)->name)));
    3575:   PetscCall(PetscStrallocpy(b->lname, (char **)&((*bNew)->lname)));
    3576:   (*bNew)->type  = b->type;
    3577:   (*bNew)->label = b->label;
    3578:   (*bNew)->Nv    = b->Nv;
    3579:   PetscCall(PetscMalloc1(b->Nv, &(*bNew)->values));
    3580:   PetscCall(PetscArraycpy((*bNew)->values, b->values, b->Nv));
    3581:   (*bNew)->field = b->field;
    3582:   (*bNew)->Nc    = b->Nc;
    3583:   PetscCall(PetscMalloc1(b->Nc, &(*bNew)->comps));
    3584:   PetscCall(PetscArraycpy((*bNew)->comps, b->comps, b->Nc));
    3585:   (*bNew)->func   = b->func;
    3586:   (*bNew)->func_t = b->func_t;
    3587:   (*bNew)->ctx    = b->ctx;
    3588:   PetscFunctionReturn(PETSC_SUCCESS);
    3589: }

    3591: /*@
    3592:   PetscDSCopyBoundary - Copy all boundary condition objects to the new `PetscDS`

    3594:   Not Collective

    3596:   Input Parameters:
    3597: + ds        - The source `PetscDS` object
    3598: . numFields - The number of selected fields, or `PETSC_DEFAULT` for all fields
    3599: - fields    - The selected fields, or `NULL` for all fields

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

    3604:   Level: intermediate

    3606: .seealso: `PetscDS`, `DMBoundary`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3607: @*/
    3608: PetscErrorCode PetscDSCopyBoundary(PetscDS ds, PetscInt numFields, const PetscInt fields[], PetscDS newds)
    3609: {
    3610:   DSBoundary b, *lastnext;

    3612:   PetscFunctionBegin;
    3615:   if (ds == newds) PetscFunctionReturn(PETSC_SUCCESS);
    3616:   PetscCall(PetscDSDestroyBoundary(newds));
    3617:   lastnext = &newds->boundary;
    3618:   for (b = ds->boundary; b; b = b->next) {
    3619:     DSBoundary bNew;
    3620:     PetscInt   fieldNew = -1;

    3622:     if (numFields > 0 && fields) {
    3623:       PetscInt f;

    3625:       for (f = 0; f < numFields; ++f)
    3626:         if (b->field == fields[f]) break;
    3627:       if (f == numFields) continue;
    3628:       fieldNew = f;
    3629:     }
    3630:     PetscCall(DSBoundaryDuplicate_Internal(b, &bNew));
    3631:     bNew->field = fieldNew < 0 ? b->field : fieldNew;
    3632:     *lastnext   = bNew;
    3633:     lastnext    = &bNew->next;
    3634:   }
    3635:   PetscFunctionReturn(PETSC_SUCCESS);
    3636: }

    3638: /*@
    3639:   PetscDSDestroyBoundary - Remove all `DMBoundary` objects from the `PetscDS`

    3641:   Not Collective

    3643:   Input Parameter:
    3644: . ds - The `PetscDS` object

    3646:   Level: intermediate

    3648: .seealso: `PetscDS`, `DMBoundary`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`
    3649: @*/
    3650: PetscErrorCode PetscDSDestroyBoundary(PetscDS ds)
    3651: {
    3652:   DSBoundary next = ds->boundary;

    3654:   PetscFunctionBegin;
    3655:   while (next) {
    3656:     DSBoundary b = next;

    3658:     next = b->next;
    3659:     PetscCall(PetscWeakFormDestroy(&b->wf));
    3660:     PetscCall(PetscFree(b->name));
    3661:     PetscCall(PetscFree(b->lname));
    3662:     PetscCall(PetscFree(b->values));
    3663:     PetscCall(PetscFree(b->comps));
    3664:     PetscCall(PetscFree(b));
    3665:   }
    3666:   PetscFunctionReturn(PETSC_SUCCESS);
    3667: }

    3669: /*@
    3670:   PetscDSSelectDiscretizations - Copy discretizations to the new `PetscDS` with different field layout

    3672:   Not Collective

    3674:   Input Parameters:
    3675: + prob      - The `PetscDS` object
    3676: . numFields - Number of new fields
    3677: . fields    - Old field number for each new field
    3678: . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
    3679: - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit

    3681:   Output Parameter:
    3682: . newprob - The `PetscDS` copy

    3684:   Level: intermediate

    3686: .seealso: `PetscDS`, `PetscDSSelectEquations()`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3687: @*/
    3688: PetscErrorCode PetscDSSelectDiscretizations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscInt minDegree, PetscInt maxDegree, PetscDS newprob)
    3689: {
    3690:   PetscInt Nf, Nfn, fn;

    3692:   PetscFunctionBegin;
    3694:   if (fields) PetscAssertPointer(fields, 3);
    3696:   PetscCall(PetscDSGetNumFields(prob, &Nf));
    3697:   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
    3698:   numFields = numFields < 0 ? Nf : numFields;
    3699:   for (fn = 0; fn < numFields; ++fn) {
    3700:     const PetscInt f = fields ? fields[fn] : fn;
    3701:     PetscObject    disc;
    3702:     PetscClassId   id;

    3704:     if (f >= Nf) continue;
    3705:     PetscCall(PetscDSGetDiscretization(prob, f, &disc));
    3706:     PetscCallContinue(PetscObjectGetClassId(disc, &id));
    3707:     if (id == PETSCFE_CLASSID) {
    3708:       PetscFE fe;

    3710:       PetscCall(PetscFELimitDegree((PetscFE)disc, minDegree, maxDegree, &fe));
    3711:       PetscCall(PetscDSSetDiscretization(newprob, fn, (PetscObject)fe));
    3712:       PetscCall(PetscFEDestroy(&fe));
    3713:     } else {
    3714:       PetscCall(PetscDSSetDiscretization(newprob, fn, disc));
    3715:     }
    3716:   }
    3717:   PetscFunctionReturn(PETSC_SUCCESS);
    3718: }

    3720: /*@
    3721:   PetscDSSelectEquations - Copy pointwise function pointers to the new `PetscDS` with different field layout

    3723:   Not Collective

    3725:   Input Parameters:
    3726: + prob      - The `PetscDS` object
    3727: . numFields - Number of new fields
    3728: - fields    - Old field number for each new field

    3730:   Output Parameter:
    3731: . newprob - The `PetscDS` copy

    3733:   Level: intermediate

    3735: .seealso: `PetscDS`, `PetscDSSelectDiscretizations()`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3736: @*/
    3737: PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
    3738: {
    3739:   PetscInt Nf, Nfn, fn, gn;

    3741:   PetscFunctionBegin;
    3743:   if (fields) PetscAssertPointer(fields, 3);
    3745:   PetscCall(PetscDSGetNumFields(prob, &Nf));
    3746:   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
    3747:   PetscCheck(numFields <= Nfn, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_SIZ, "Number of fields %" PetscInt_FMT " to transfer must not be greater than the total number of fields %" PetscInt_FMT, numFields, Nfn);
    3748:   for (fn = 0; fn < numFields; ++fn) {
    3749:     const PetscInt  f = fields ? fields[fn] : fn;
    3750:     PetscPointFn   *obj;
    3751:     PetscPointFn   *f0, *f1;
    3752:     PetscBdPointFn *f0Bd, *f1Bd;
    3753:     PetscRiemannFn *r;

    3755:     if (f >= Nf) continue;
    3756:     PetscCall(PetscDSGetObjective(prob, f, &obj));
    3757:     PetscCall(PetscDSGetResidual(prob, f, &f0, &f1));
    3758:     PetscCall(PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd));
    3759:     PetscCall(PetscDSGetRiemannSolver(prob, f, &r));
    3760:     PetscCall(PetscDSSetObjective(newprob, fn, obj));
    3761:     PetscCall(PetscDSSetResidual(newprob, fn, f0, f1));
    3762:     PetscCall(PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd));
    3763:     PetscCall(PetscDSSetRiemannSolver(newprob, fn, r));
    3764:     for (gn = 0; gn < numFields; ++gn) {
    3765:       const PetscInt     g = fields ? fields[gn] : gn;
    3766:       PetscPointJacFn   *g0, *g1, *g2, *g3;
    3767:       PetscPointJacFn   *g0p, *g1p, *g2p, *g3p;
    3768:       PetscBdPointJacFn *g0Bd, *g1Bd, *g2Bd, *g3Bd;

    3770:       if (g >= Nf) continue;
    3771:       PetscCall(PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3));
    3772:       PetscCall(PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p));
    3773:       PetscCall(PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd));
    3774:       PetscCall(PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3));
    3775:       PetscCall(PetscDSSetJacobianPreconditioner(newprob, fn, gn, g0p, g1p, g2p, g3p));
    3776:       PetscCall(PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd));
    3777:     }
    3778:   }
    3779:   PetscFunctionReturn(PETSC_SUCCESS);
    3780: }

    3782: /*@
    3783:   PetscDSCopyEquations - Copy all pointwise function pointers to another `PetscDS`

    3785:   Not Collective

    3787:   Input Parameter:
    3788: . prob - The `PetscDS` object

    3790:   Output Parameter:
    3791: . newprob - The `PetscDS` copy

    3793:   Level: intermediate

    3795: .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3796: @*/
    3797: PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
    3798: {
    3799:   PetscWeakForm wf, newwf;
    3800:   PetscInt      Nf, Ng;

    3802:   PetscFunctionBegin;
    3805:   PetscCall(PetscDSGetNumFields(prob, &Nf));
    3806:   PetscCall(PetscDSGetNumFields(newprob, &Ng));
    3807:   PetscCheck(Nf == Ng, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %" PetscInt_FMT " != %" PetscInt_FMT, Nf, Ng);
    3808:   PetscCall(PetscDSGetWeakForm(prob, &wf));
    3809:   PetscCall(PetscDSGetWeakForm(newprob, &newwf));
    3810:   PetscCall(PetscWeakFormCopy(wf, newwf));
    3811:   PetscFunctionReturn(PETSC_SUCCESS);
    3812: }

    3814: /*@
    3815:   PetscDSCopyConstants - Copy all constants set with `PetscDSSetConstants()` to another `PetscDS`

    3817:   Not Collective

    3819:   Input Parameter:
    3820: . prob - The `PetscDS` object

    3822:   Output Parameter:
    3823: . newprob - The `PetscDS` copy

    3825:   Level: intermediate

    3827: .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3828: @*/
    3829: PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
    3830: {
    3831:   PetscInt           Nc;
    3832:   const PetscScalar *constants;

    3834:   PetscFunctionBegin;
    3837:   PetscCall(PetscDSGetConstants(prob, &Nc, &constants));
    3838:   PetscCall(PetscDSSetConstants(newprob, Nc, (PetscScalar *)constants));
    3839:   PetscFunctionReturn(PETSC_SUCCESS);
    3840: }

    3842: /*@
    3843:   PetscDSCopyExactSolutions - Copy all exact solutions set with `PetscDSSetExactSolution()` and `PetscDSSetExactSolutionTimeDerivative()` to another `PetscDS`

    3845:   Not Collective

    3847:   Input Parameter:
    3848: . ds - The `PetscDS` object

    3850:   Output Parameter:
    3851: . newds - The `PetscDS` copy

    3853:   Level: intermediate

    3855: .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSCopyBounds()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3856: @*/
    3857: PetscErrorCode PetscDSCopyExactSolutions(PetscDS ds, PetscDS newds)
    3858: {
    3859:   PetscSimplePointFn *sol;
    3860:   void               *ctx;
    3861:   PetscInt            Nf, f;

    3863:   PetscFunctionBegin;
    3866:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    3867:   for (f = 0; f < Nf; ++f) {
    3868:     PetscCall(PetscDSGetExactSolution(ds, f, &sol, &ctx));
    3869:     PetscCall(PetscDSSetExactSolution(newds, f, sol, ctx));
    3870:     PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, f, &sol, &ctx));
    3871:     PetscCall(PetscDSSetExactSolutionTimeDerivative(newds, f, sol, ctx));
    3872:   }
    3873:   PetscFunctionReturn(PETSC_SUCCESS);
    3874: }

    3876: /*@
    3877:   PetscDSCopyBounds - Copy lower and upper solution bounds set with `PetscDSSetLowerBound()` and `PetscDSSetLowerBound()` to another `PetscDS`

    3879:   Not Collective

    3881:   Input Parameter:
    3882: . ds - The `PetscDS` object

    3884:   Output Parameter:
    3885: . newds - The `PetscDS` copy

    3887:   Level: intermediate

    3889: .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSCopyExactSolutions()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
    3890: @*/
    3891: PetscErrorCode PetscDSCopyBounds(PetscDS ds, PetscDS newds)
    3892: {
    3893:   PetscSimplePointFn *bound;
    3894:   void               *ctx;
    3895:   PetscInt            Nf, f;

    3897:   PetscFunctionBegin;
    3900:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    3901:   for (f = 0; f < Nf; ++f) {
    3902:     PetscCall(PetscDSGetLowerBound(ds, f, &bound, &ctx));
    3903:     PetscCall(PetscDSSetLowerBound(newds, f, bound, ctx));
    3904:     PetscCall(PetscDSGetUpperBound(ds, f, &bound, &ctx));
    3905:     PetscCall(PetscDSSetUpperBound(newds, f, bound, ctx));
    3906:   }
    3907:   PetscFunctionReturn(PETSC_SUCCESS);
    3908: }

    3910: PetscErrorCode PetscDSCopy(PetscDS ds, PetscInt minDegree, PetscInt maxDegree, DM dmNew, PetscDS dsNew)
    3911: {
    3912:   DSBoundary b;
    3913:   PetscInt   cdim, Nf, f, d;
    3914:   PetscBool  isCohesive;
    3915:   void      *ctx;

    3917:   PetscFunctionBegin;
    3918:   PetscCall(PetscDSCopyConstants(ds, dsNew));
    3919:   PetscCall(PetscDSCopyExactSolutions(ds, dsNew));
    3920:   PetscCall(PetscDSCopyBounds(ds, dsNew));
    3921:   PetscCall(PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, minDegree, maxDegree, dsNew));
    3922:   PetscCall(PetscDSCopyEquations(ds, dsNew));
    3923:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    3924:   for (f = 0; f < Nf; ++f) {
    3925:     PetscCall(PetscDSGetContext(ds, f, &ctx));
    3926:     PetscCall(PetscDSSetContext(dsNew, f, ctx));
    3927:     PetscCall(PetscDSGetCohesive(ds, f, &isCohesive));
    3928:     PetscCall(PetscDSSetCohesive(dsNew, f, isCohesive));
    3929:     PetscCall(PetscDSGetJetDegree(ds, f, &d));
    3930:     PetscCall(PetscDSSetJetDegree(dsNew, f, d));
    3931:   }
    3932:   if (Nf) {
    3933:     PetscCall(PetscDSGetCoordinateDimension(ds, &cdim));
    3934:     PetscCall(PetscDSSetCoordinateDimension(dsNew, cdim));
    3935:   }
    3936:   PetscCall(PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew));
    3937:   for (b = dsNew->boundary; b; b = b->next) {
    3938:     PetscCall(DMGetLabel(dmNew, b->lname, &b->label));
    3939:     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
    3940:     //PetscCheck(b->label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
    3941:   }
    3942:   PetscFunctionReturn(PETSC_SUCCESS);
    3943: }

    3945: PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
    3946: {
    3947:   PetscInt dim, Nf, f;

    3949:   PetscFunctionBegin;
    3951:   PetscAssertPointer(subprob, 3);
    3952:   if (height == 0) {
    3953:     *subprob = prob;
    3954:     PetscFunctionReturn(PETSC_SUCCESS);
    3955:   }
    3956:   PetscCall(PetscDSGetNumFields(prob, &Nf));
    3957:   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
    3958:   PetscCheck(height <= dim, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %" PetscInt_FMT "], not %" PetscInt_FMT, dim, height);
    3959:   if (!prob->subprobs) PetscCall(PetscCalloc1(dim, &prob->subprobs));
    3960:   if (!prob->subprobs[height - 1]) {
    3961:     PetscInt cdim;

    3963:     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)prob), &prob->subprobs[height - 1]));
    3964:     PetscCall(PetscDSGetCoordinateDimension(prob, &cdim));
    3965:     PetscCall(PetscDSSetCoordinateDimension(prob->subprobs[height - 1], cdim));
    3966:     for (f = 0; f < Nf; ++f) {
    3967:       PetscFE      subfe;
    3968:       PetscObject  obj;
    3969:       PetscClassId id;

    3971:       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
    3972:       PetscCall(PetscObjectGetClassId(obj, &id));
    3973:       PetscCheck(id == PETSCFE_CLASSID, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %" PetscInt_FMT, f);
    3974:       PetscCall(PetscFEGetHeightSubspace((PetscFE)obj, height, &subfe));
    3975:       PetscCall(PetscDSSetDiscretization(prob->subprobs[height - 1], f, (PetscObject)subfe));
    3976:     }
    3977:   }
    3978:   *subprob = prob->subprobs[height - 1];
    3979:   PetscFunctionReturn(PETSC_SUCCESS);
    3980: }

    3982: PetscErrorCode PetscDSPermuteQuadPoint(PetscDS ds, PetscInt ornt, PetscInt field, PetscInt q, PetscInt *qperm)
    3983: {
    3984:   IS              permIS;
    3985:   PetscQuadrature quad;
    3986:   DMPolytopeType  ct;
    3987:   const PetscInt *perm;
    3988:   PetscInt        Na, Nq;

    3990:   PetscFunctionBeginHot;
    3991:   PetscCall(PetscFEGetQuadrature((PetscFE)ds->disc[field], &quad));
    3992:   PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
    3993:   PetscCall(PetscQuadratureGetCellType(quad, &ct));
    3994:   PetscCheck(q >= 0 && q < Nq, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Quadrature point %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", q, Nq);
    3995:   Na = DMPolytopeTypeGetNumArrangements(ct) / 2;
    3996:   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);
    3997:   if (!ds->quadPerm[(PetscInt)ct]) PetscCall(PetscQuadratureComputePermutations(quad, NULL, &ds->quadPerm[(PetscInt)ct]));
    3998:   permIS = ds->quadPerm[(PetscInt)ct][ornt + Na];
    3999:   PetscCall(ISGetIndices(permIS, &perm));
    4000:   *qperm = perm[q];
    4001:   PetscCall(ISRestoreIndices(permIS, &perm));
    4002:   PetscFunctionReturn(PETSC_SUCCESS);
    4003: }

    4005: PetscErrorCode PetscDSGetDiscType_Internal(PetscDS ds, PetscInt f, PetscDiscType *disctype)
    4006: {
    4007:   PetscObject  obj;
    4008:   PetscClassId id;
    4009:   PetscInt     Nf;

    4011:   PetscFunctionBegin;
    4013:   PetscAssertPointer(disctype, 3);
    4014:   *disctype = PETSC_DISC_NONE;
    4015:   PetscCall(PetscDSGetNumFields(ds, &Nf));
    4016:   PetscCheck(f < Nf, PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_SIZ, "Field %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
    4017:   PetscCall(PetscDSGetDiscretization(ds, f, &obj));
    4018:   if (obj) {
    4019:     PetscCall(PetscObjectGetClassId(obj, &id));
    4020:     if (id == PETSCFE_CLASSID) *disctype = PETSC_DISC_FE;
    4021:     else *disctype = PETSC_DISC_FV;
    4022:   }
    4023:   PetscFunctionReturn(PETSC_SUCCESS);
    4024: }

    4026: static PetscErrorCode PetscDSDestroy_Basic(PetscDS ds)
    4027: {
    4028:   PetscFunctionBegin;
    4029:   PetscCall(PetscFree(ds->data));
    4030:   PetscFunctionReturn(PETSC_SUCCESS);
    4031: }

    4033: static PetscErrorCode PetscDSInitialize_Basic(PetscDS ds)
    4034: {
    4035:   PetscFunctionBegin;
    4036:   ds->ops->setfromoptions = NULL;
    4037:   ds->ops->setup          = NULL;
    4038:   ds->ops->view           = NULL;
    4039:   ds->ops->destroy        = PetscDSDestroy_Basic;
    4040:   PetscFunctionReturn(PETSC_SUCCESS);
    4041: }

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

    4046:   Level: intermediate

    4048: .seealso: `PetscDSType`, `PetscDSCreate()`, `PetscDSSetType()`
    4049: M*/

    4051: PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS ds)
    4052: {
    4053:   PetscDS_Basic *b;

    4055:   PetscFunctionBegin;
    4057:   PetscCall(PetscNew(&b));
    4058:   ds->data = b;

    4060:   PetscCall(PetscDSInitialize_Basic(ds));
    4061:   PetscFunctionReturn(PETSC_SUCCESS);
    4062: }