Actual source code: dtds.c
petsc-3.13.6 2020-09-29
Report Typos and Errors

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

      3: PetscClassId PETSCDS_CLASSID = 0;

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

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

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

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

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

     24:   Not Collective

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

     30:   Notes:
     31:   PetscDSRegister() may be called multiple times to add several user-defined PetscDSs

     33:   Sample usage:
     34: .vb
     35:     PetscDSRegister("my_ds", MyPetscDSCreate);
     36: .ve

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

     48:   Level: advanced

     50:    Not available from Fortran

     52: .seealso: PetscDSRegisterAll(), PetscDSRegisterDestroy()

     54: @*/
     55: PetscErrorCode PetscDSRegister(const char sname[], PetscErrorCode (*function)(PetscDS))
     56: {

     60:   PetscFunctionListAdd(&PetscDSList, sname, function);
     61:   return(0);
     62: }

     64: /*@C
     65:   PetscDSSetType - Builds a particular PetscDS

     67:   Collective on prob

     69:   Input Parameters:
     70: + prob - The PetscDS object
     71: - name - The kind of system

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

     76:   Level: intermediate

     78:    Not available from Fortran

     80: .seealso: PetscDSGetType(), PetscDSCreate()
     81: @*/
     82: PetscErrorCode PetscDSSetType(PetscDS prob, PetscDSType name)
     83: {
     84:   PetscErrorCode (*r)(PetscDS);
     85:   PetscBool      match;

     90:   PetscObjectTypeCompare((PetscObject) prob, name, &match);
     91:   if (match) return(0);

     93:   PetscDSRegisterAll();
     94:   PetscFunctionListFind(PetscDSList, name, &r);
     95:   if (!r) SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDS type: %s", name);

     97:   if (prob->ops->destroy) {
     98:     (*prob->ops->destroy)(prob);
     99:     prob->ops->destroy = NULL;
    100:   }
    101:   (*r)(prob);
    102:   PetscObjectChangeTypeName((PetscObject) prob, name);
    103:   return(0);
    104: }

    106: /*@C
    107:   PetscDSGetType - Gets the PetscDS type name (as a string) from the object.

    109:   Not Collective

    111:   Input Parameter:
    112: . prob  - The PetscDS

    114:   Output Parameter:
    115: . name - The PetscDS type name

    117:   Level: intermediate

    119:    Not available from Fortran

    121: .seealso: PetscDSSetType(), PetscDSCreate()
    122: @*/
    123: PetscErrorCode PetscDSGetType(PetscDS prob, PetscDSType *name)
    124: {

    130:   PetscDSRegisterAll();
    131:   *name = ((PetscObject) prob)->type_name;
    132:   return(0);
    133: }

    135: static PetscErrorCode PetscDSView_Ascii(PetscDS prob, PetscViewer viewer)
    136: {
    137:   PetscViewerFormat  format;
    138:   const PetscScalar *constants;
    139:   PetscInt           numConstants, f;
    140:   PetscErrorCode     ierr;

    143:   PetscViewerGetFormat(viewer, &format);
    144:   PetscViewerASCIIPrintf(viewer, "Discrete System with %d fields\n", prob->Nf);
    145:   PetscViewerASCIIPushTab(viewer);
    146:   PetscViewerASCIIPrintf(viewer, "  cell total dim %D total comp %D\n", prob->totDim, prob->totComp);
    147:   if (prob->isHybrid) {PetscViewerASCIIPrintf(viewer, "  hybrid cell\n");}
    148:   for (f = 0; f < prob->Nf; ++f) {
    149:     DSBoundary      b;
    150:     PetscObject     obj;
    151:     PetscClassId    id;
    152:     PetscQuadrature q;
    153:     const char     *name;
    154:     PetscInt        Nc, Nq, Nqc;

    156:     PetscDSGetDiscretization(prob, f, &obj);
    157:     PetscObjectGetClassId(obj, &id);
    158:     PetscObjectGetName(obj, &name);
    159:     PetscViewerASCIIPrintf(viewer, "Field %s", name ? name : "<unknown>");
    160:     PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
    161:     if (id == PETSCFE_CLASSID)      {
    162:       PetscFEGetNumComponents((PetscFE) obj, &Nc);
    163:       PetscFEGetQuadrature((PetscFE) obj, &q);
    164:       PetscViewerASCIIPrintf(viewer, " FEM");
    165:     } else if (id == PETSCFV_CLASSID) {
    166:       PetscFVGetNumComponents((PetscFV) obj, &Nc);
    167:       PetscFVGetQuadrature((PetscFV) obj, &q);
    168:       PetscViewerASCIIPrintf(viewer, " FVM");
    169:     }
    170:     else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
    171:     if (Nc > 1) {PetscViewerASCIIPrintf(viewer, "%D components", Nc);}
    172:     else        {PetscViewerASCIIPrintf(viewer, "%D component ", Nc);}
    173:     if (prob->implicit[f]) {PetscViewerASCIIPrintf(viewer, " (implicit)");}
    174:     else                   {PetscViewerASCIIPrintf(viewer, " (explicit)");}
    175:     if (q) {
    176:       PetscQuadratureGetData(q, NULL, &Nqc, &Nq, NULL, NULL);
    177:       PetscViewerASCIIPrintf(viewer, " (Nq %D Nqc %D)", Nq, Nqc);
    178:     }
    179:     PetscViewerASCIIPrintf(viewer, "\n");
    180:     PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
    181:     PetscViewerASCIIPushTab(viewer);
    182:     if (id == PETSCFE_CLASSID)      {PetscFEView((PetscFE) obj, viewer);}
    183:     else if (id == PETSCFV_CLASSID) {PetscFVView((PetscFV) obj, viewer);}
    184:     PetscViewerASCIIPopTab(viewer);

    186:     for (b = prob->boundary; b; b = b->next) {
    187:       PetscInt c, i;

    189:       if (b->field != f) continue;
    190:       PetscViewerASCIIPushTab(viewer);
    191:       PetscViewerASCIIPrintf(viewer, "Boundary %s (%s) %s\n", b->name, b->labelname, DMBoundaryConditionTypes[b->type]);
    192:       if (!b->numcomps) {
    193:         PetscViewerASCIIPrintf(viewer, "  all components\n");
    194:       } else {
    195:         PetscViewerASCIIPrintf(viewer, "  components: ");
    196:         PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
    197:         for (c = 0; c < b->numcomps; ++c) {
    198:           if (c > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
    199:           PetscViewerASCIIPrintf(viewer, "%D", b->comps[c]);
    200:         }
    201:         PetscViewerASCIIPrintf(viewer, "\n");
    202:         PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
    203:       }
    204:       PetscViewerASCIIPrintf(viewer, "  ids: ");
    205:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
    206:       for (i = 0; i < b->numids; ++i) {
    207:         if (i > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
    208:         PetscViewerASCIIPrintf(viewer, "%D", b->ids[i]);
    209:       }
    210:       PetscViewerASCIIPrintf(viewer, "\n");
    211:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
    212:       PetscViewerASCIIPopTab(viewer);
    213:     }
    214:   }
    215:   PetscDSGetConstants(prob, &numConstants, &constants);
    216:   if (numConstants) {
    217:     PetscViewerASCIIPrintf(viewer, "%D constants\n", numConstants);
    218:     PetscViewerASCIIPushTab(viewer);
    219:     for (f = 0; f < numConstants; ++f) {PetscViewerASCIIPrintf(viewer, "%g\n", (double) PetscRealPart(constants[f]));}
    220:     PetscViewerASCIIPopTab(viewer);
    221:   }
    222:   PetscViewerASCIIPopTab(viewer);
    223:   return(0);
    224: }

    226: /*@C
    227:    PetscDSViewFromOptions - View from Options

    229:    Collective on PetscDS

    231:    Input Parameters:
    232: +  A - the PetscDS object
    233: .  obj - Optional object
    234: -  name - command line option

    236:    Level: intermediate
    237: .seealso:  PetscDS, PetscDSView, PetscObjectViewFromOptions(), PetscDSCreate()
    238: @*/
    239: PetscErrorCode  PetscDSViewFromOptions(PetscDS A,PetscObject obj,const char name[])
    240: {

    245:   PetscObjectViewFromOptions((PetscObject)A,obj,name);
    246:   return(0);
    247: }

    249: /*@C
    250:   PetscDSView - Views a PetscDS

    252:   Collective on prob

    254:   Input Parameter:
    255: + prob - the PetscDS object to view
    256: - v  - the viewer

    258:   Level: developer

    260: .seealso PetscDSDestroy()
    261: @*/
    262: PetscErrorCode PetscDSView(PetscDS prob, PetscViewer v)
    263: {
    264:   PetscBool      iascii;

    269:   if (!v) {PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) prob), &v);}
    271:   PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &iascii);
    272:   if (iascii) {PetscDSView_Ascii(prob, v);}
    273:   if (prob->ops->view) {(*prob->ops->view)(prob, v);}
    274:   return(0);
    275: }

    277: /*@
    278:   PetscDSSetFromOptions - sets parameters in a PetscDS from the options database

    280:   Collective on prob

    282:   Input Parameter:
    283: . prob - the PetscDS object to set options for

    285:   Options Database:
    286: + -petscds_type <type>     : Set the DS type
    287: . -petscds_view <view opt> : View the DS
    288: . -petscds_jac_pre         : Turn formation of a separate Jacobian preconditioner on and off
    289: . -bc_<name> <ids>         : Specify a list of label ids for a boundary condition
    290: - -bc_<name>_comp <comps>  : Specify a list of field components to constrain for a boundary condition

    292:   Level: developer

    294: .seealso PetscDSView()
    295: @*/
    296: PetscErrorCode PetscDSSetFromOptions(PetscDS prob)
    297: {
    298:   DSBoundary     b;
    299:   const char    *defaultType;
    300:   char           name[256];
    301:   PetscBool      flg;

    306:   if (!((PetscObject) prob)->type_name) {
    307:     defaultType = PETSCDSBASIC;
    308:   } else {
    309:     defaultType = ((PetscObject) prob)->type_name;
    310:   }
    311:   PetscDSRegisterAll();

    313:   PetscObjectOptionsBegin((PetscObject) prob);
    314:   for (b = prob->boundary; b; b = b->next) {
    315:     char       optname[1024];
    316:     PetscInt   ids[1024], len = 1024;
    317:     PetscBool  flg;

    319:     PetscSNPrintf(optname, sizeof(optname), "-bc_%s", b->name);
    320:     PetscMemzero(ids, sizeof(ids));
    321:     PetscOptionsIntArray(optname, "List of boundary IDs", "", ids, &len, &flg);
    322:     if (flg) {
    323:       b->numids = len;
    324:       PetscFree(b->ids);
    325:       PetscMalloc1(len, &b->ids);
    326:       PetscArraycpy(b->ids, ids, len);
    327:     }
    328:     len = 1024;
    329:     PetscSNPrintf(optname, sizeof(optname), "-bc_%s_comp", b->name);
    330:     PetscMemzero(ids, sizeof(ids));
    331:     PetscOptionsIntArray(optname, "List of boundary field components", "", ids, &len, &flg);
    332:     if (flg) {
    333:       b->numcomps = len;
    334:       PetscFree(b->comps);
    335:       PetscMalloc1(len, &b->comps);
    336:       PetscArraycpy(b->comps, ids, len);
    337:     }
    338:   }
    339:   PetscOptionsFList("-petscds_type", "Discrete System", "PetscDSSetType", PetscDSList, defaultType, name, 256, &flg);
    340:   if (flg) {
    341:     PetscDSSetType(prob, name);
    342:   } else if (!((PetscObject) prob)->type_name) {
    343:     PetscDSSetType(prob, defaultType);
    344:   }
    345:   PetscOptionsBool("-petscds_jac_pre", "Discrete System", "PetscDSUseJacobianPreconditioner", prob->useJacPre, &prob->useJacPre, &flg);
    346:   if (prob->ops->setfromoptions) {(*prob->ops->setfromoptions)(prob);}
    347:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
    348:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) prob);
    349:   PetscOptionsEnd();
    350:   if (prob->Nf) {PetscDSViewFromOptions(prob, NULL, "-petscds_view");}
    351:   return(0);
    352: }

    354: /*@C
    355:   PetscDSSetUp - Construct data structures for the PetscDS

    357:   Collective on prob

    359:   Input Parameter:
    360: . prob - the PetscDS object to setup

    362:   Level: developer

    364: .seealso PetscDSView(), PetscDSDestroy()
    365: @*/
    366: PetscErrorCode PetscDSSetUp(PetscDS prob)
    367: {
    368:   const PetscInt Nf = prob->Nf;
    369:   PetscInt       dim, dimEmbed, NbMax = 0, NcMax = 0, NqMax = 0, NsMax = 1, f;

    374:   if (prob->setup) return(0);
    375:   /* Calculate sizes */
    376:   PetscDSGetSpatialDimension(prob, &dim);
    377:   PetscDSGetCoordinateDimension(prob, &dimEmbed);
    378:   prob->totDim = prob->totComp = 0;
    379:   PetscMalloc2(Nf,&prob->Nc,Nf,&prob->Nb);
    380:   PetscCalloc2(Nf+1,&prob->off,Nf+1,&prob->offDer);
    381:   PetscMalloc2(Nf,&prob->T,Nf,&prob->Tf);
    382:   for (f = 0; f < Nf; ++f) {
    383:     PetscObject     obj;
    384:     PetscClassId    id;
    385:     PetscQuadrature q;
    386:     PetscInt        Nq = 0, Nb, Nc;

    388:     PetscDSGetDiscretization(prob, f, &obj);
    389:     PetscObjectGetClassId(obj, &id);
    390:     if (id == PETSCFE_CLASSID)      {
    391:       PetscFE fe = (PetscFE) obj;

    393:       PetscFEGetQuadrature(fe, &q);
    394:       PetscFEGetDimension(fe, &Nb);
    395:       PetscFEGetNumComponents(fe, &Nc);
    396:       PetscFEGetCellTabulation(fe, &prob->T[f]);
    397:       PetscFEGetFaceTabulation(fe, &prob->Tf[f]);
    398:     } else if (id == PETSCFV_CLASSID) {
    399:       PetscFV fv = (PetscFV) obj;

    401:       PetscFVGetQuadrature(fv, &q);
    402:       PetscFVGetNumComponents(fv, &Nc);
    403:       Nb   = Nc;
    404:       PetscFVGetCellTabulation(fv, &prob->T[f]);
    405:       /* TODO: should PetscFV also have face tabulation? Otherwise there will be a null pointer in prob->basisFace */
    406:     } else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
    407:     prob->Nc[f]       = Nc;
    408:     prob->Nb[f]       = Nb;
    409:     prob->off[f+1]    = Nc     + prob->off[f];
    410:     prob->offDer[f+1] = Nc*dim + prob->offDer[f];
    411:     if (q) {PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);}
    412:     NqMax          = PetscMax(NqMax, Nq);
    413:     NbMax          = PetscMax(NbMax, Nb);
    414:     NcMax          = PetscMax(NcMax, Nc);
    415:     prob->totDim  += Nb;
    416:     prob->totComp += Nc;
    417:     /* There are two faces for all fields but the cohesive field on a hybrid cell */
    418:     if (prob->isHybrid && (f < Nf-1)) prob->totDim += Nb;
    419:   }
    420:   /* Allocate works space */
    421:   if (prob->isHybrid) NsMax = 2;
    422:   PetscMalloc3(NsMax*prob->totComp,&prob->u,NsMax*prob->totComp,&prob->u_t,NsMax*prob->totComp*dimEmbed,&prob->u_x);
    423:   PetscMalloc5(dimEmbed,&prob->x,NbMax*NcMax,&prob->basisReal,NbMax*NcMax*dimEmbed,&prob->basisDerReal,NbMax*NcMax,&prob->testReal,NbMax*NcMax*dimEmbed,&prob->testDerReal);
    424:   PetscMalloc6(NsMax*NqMax*NcMax,&prob->f0,NsMax*NqMax*NcMax*dim,&prob->f1,
    425:                       NsMax*NsMax*NqMax*NcMax*NcMax,&prob->g0,NsMax*NsMax*NqMax*NcMax*NcMax*dim,&prob->g1,
    426:                       NsMax*NsMax*NqMax*NcMax*NcMax*dim,&prob->g2,NsMax*NsMax*NqMax*NcMax*NcMax*dim*dim,&prob->g3);
    427:   if (prob->ops->setup) {(*prob->ops->setup)(prob);}
    428:   prob->setup = PETSC_TRUE;
    429:   return(0);
    430: }

    432: static PetscErrorCode PetscDSDestroyStructs_Static(PetscDS prob)
    433: {

    437:   PetscFree2(prob->Nc,prob->Nb);
    438:   PetscFree2(prob->off,prob->offDer);
    439:   PetscFree2(prob->T,prob->Tf);
    440:   PetscFree3(prob->u,prob->u_t,prob->u_x);
    441:   PetscFree5(prob->x,prob->basisReal, prob->basisDerReal,prob->testReal,prob->testDerReal);
    442:   PetscFree6(prob->f0,prob->f1,prob->g0,prob->g1,prob->g2,prob->g3);
    443:   return(0);
    444: }

    446: static PetscErrorCode PetscDSEnlarge_Static(PetscDS prob, PetscInt NfNew)
    447: {
    448:   PetscObject      *tmpd;
    449:   PetscBool        *tmpi;
    450:   PetscPointFunc   *tmpobj, *tmpf, *tmpup;
    451:   PetscPointJac    *tmpg, *tmpgp, *tmpgt;
    452:   PetscBdPointFunc *tmpfbd;
    453:   PetscBdPointJac  *tmpgbd;
    454:   PetscRiemannFunc *tmpr;
    455:   PetscSimplePointFunc *tmpexactSol;
    456:   void                **tmpexactCtx;
    457:   void            **tmpctx;
    458:   PetscInt          Nf = prob->Nf, f;
    459:   PetscErrorCode    ierr;

    462:   if (Nf >= NfNew) return(0);
    463:   prob->setup = PETSC_FALSE;
    464:   PetscDSDestroyStructs_Static(prob);
    465:   PetscMalloc2(NfNew, &tmpd, NfNew, &tmpi);
    466:   for (f = 0; f < Nf; ++f) {tmpd[f] = prob->disc[f]; tmpi[f] = prob->implicit[f];}
    467:   for (f = Nf; f < NfNew; ++f) {tmpd[f] = NULL; tmpi[f] = PETSC_TRUE;}
    468:   PetscFree2(prob->disc, prob->implicit);
    469:   prob->Nf        = NfNew;
    470:   prob->disc      = tmpd;
    471:   prob->implicit  = tmpi;
    472:   PetscCalloc7(NfNew, &tmpobj, NfNew*2, &tmpf, NfNew*NfNew*4, &tmpg, NfNew*NfNew*4, &tmpgp, NfNew*NfNew*4, &tmpgt, NfNew, &tmpr, NfNew, &tmpctx);
    473:   PetscCalloc1(NfNew, &tmpup);
    474:   for (f = 0; f < Nf; ++f) tmpobj[f] = prob->obj[f];
    475:   for (f = 0; f < Nf*2; ++f) tmpf[f] = prob->f[f];
    476:   for (f = 0; f < Nf*Nf*4; ++f) tmpg[f] = prob->g[f];
    477:   for (f = 0; f < Nf*Nf*4; ++f) tmpgp[f] = prob->gp[f];
    478:   for (f = 0; f < Nf; ++f) tmpr[f] = prob->r[f];
    479:   for (f = 0; f < Nf; ++f) tmpup[f] = prob->update[f];
    480:   for (f = 0; f < Nf; ++f) tmpctx[f] = prob->ctx[f];
    481:   for (f = Nf; f < NfNew; ++f) tmpobj[f] = NULL;
    482:   for (f = Nf*2; f < NfNew*2; ++f) tmpf[f] = NULL;
    483:   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpg[f] = NULL;
    484:   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpgp[f] = NULL;
    485:   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpgt[f] = NULL;
    486:   for (f = Nf; f < NfNew; ++f) tmpr[f] = NULL;
    487:   for (f = Nf; f < NfNew; ++f) tmpup[f] = NULL;
    488:   for (f = Nf; f < NfNew; ++f) tmpctx[f] = NULL;
    489:   PetscFree7(prob->obj, prob->f, prob->g, prob->gp, prob->gt, prob->r, prob->ctx);
    490:   PetscFree(prob->update);
    491:   prob->obj = tmpobj;
    492:   prob->f   = tmpf;
    493:   prob->g   = tmpg;
    494:   prob->gp  = tmpgp;
    495:   prob->gt  = tmpgt;
    496:   prob->r   = tmpr;
    497:   prob->update = tmpup;
    498:   prob->ctx = tmpctx;
    499:   PetscCalloc4(NfNew*2, &tmpfbd, NfNew*NfNew*4, &tmpgbd, NfNew, &tmpexactSol, NfNew, &tmpexactCtx);
    500:   for (f = 0; f < Nf*2; ++f) tmpfbd[f] = prob->fBd[f];
    501:   for (f = 0; f < Nf*Nf*4; ++f) tmpgbd[f] = prob->gBd[f];
    502:   for (f = 0; f < Nf; ++f) tmpexactSol[f] = prob->exactSol[f];
    503:   for (f = 0; f < Nf; ++f) tmpexactCtx[f] = prob->exactCtx[f];
    504:   for (f = Nf*2; f < NfNew*2; ++f) tmpfbd[f] = NULL;
    505:   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpgbd[f] = NULL;
    506:   for (f = Nf; f < NfNew; ++f) tmpexactSol[f] = NULL;
    507:   for (f = Nf; f < NfNew; ++f) tmpexactCtx[f] = NULL;
    508:   PetscFree4(prob->fBd, prob->gBd, prob->exactSol, prob->exactCtx);
    509:   prob->fBd = tmpfbd;
    510:   prob->gBd = tmpgbd;
    511:   prob->exactSol = tmpexactSol;
    512:   prob->exactCtx = tmpexactCtx;
    513:   return(0);
    514: }

    516: /*@
    517:   PetscDSDestroy - Destroys a PetscDS object

    519:   Collective on prob

    521:   Input Parameter:
    522: . prob - the PetscDS object to destroy

    524:   Level: developer

    526: .seealso PetscDSView()
    527: @*/
    528: PetscErrorCode PetscDSDestroy(PetscDS *prob)
    529: {
    530:   PetscInt       f;
    531:   DSBoundary     next;

    535:   if (!*prob) return(0);

    538:   if (--((PetscObject)(*prob))->refct > 0) {*prob = 0; return(0);}
    539:   ((PetscObject) (*prob))->refct = 0;
    540:   if ((*prob)->subprobs) {
    541:     PetscInt dim, d;

    543:     PetscDSGetSpatialDimension(*prob, &dim);
    544:     for (d = 0; d < dim; ++d) {PetscDSDestroy(&(*prob)->subprobs[d]);}
    545:   }
    546:   PetscFree((*prob)->subprobs);
    547:   PetscDSDestroyStructs_Static(*prob);
    548:   for (f = 0; f < (*prob)->Nf; ++f) {
    549:     PetscObjectDereference((*prob)->disc[f]);
    550:   }
    551:   PetscFree2((*prob)->disc, (*prob)->implicit);
    552:   PetscFree7((*prob)->obj,(*prob)->f,(*prob)->g,(*prob)->gp,(*prob)->gt,(*prob)->r,(*prob)->ctx);
    553:   PetscFree((*prob)->update);
    554:   PetscFree4((*prob)->fBd,(*prob)->gBd,(*prob)->exactSol,(*prob)->exactCtx);
    555:   if ((*prob)->ops->destroy) {(*(*prob)->ops->destroy)(*prob);}
    556:   next = (*prob)->boundary;
    557:   while (next) {
    558:     DSBoundary b = next;

    560:     next = b->next;
    561:     PetscFree(b->comps);
    562:     PetscFree(b->ids);
    563:     PetscFree(b->name);
    564:     PetscFree(b->labelname);
    565:     PetscFree(b);
    566:   }
    567:   PetscFree((*prob)->constants);
    568:   PetscHeaderDestroy(prob);
    569:   return(0);
    570: }

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

    575:   Collective

    577:   Input Parameter:
    578: . comm - The communicator for the PetscDS object

    580:   Output Parameter:
    581: . prob - The PetscDS object

    583:   Level: beginner

    585: .seealso: PetscDSSetType(), PETSCDSBASIC
    586: @*/
    587: PetscErrorCode PetscDSCreate(MPI_Comm comm, PetscDS *prob)
    588: {
    589:   PetscDS   p;

    594:   *prob  = NULL;
    595:   PetscDSInitializePackage();

    597:   PetscHeaderCreate(p, PETSCDS_CLASSID, "PetscDS", "Discrete System", "PetscDS", comm, PetscDSDestroy, PetscDSView);

    599:   p->Nf           = 0;
    600:   p->setup        = PETSC_FALSE;
    601:   p->numConstants = 0;
    602:   p->constants    = NULL;
    603:   p->dimEmbed     = -1;
    604:   p->useJacPre    = PETSC_TRUE;

    606:   *prob = p;
    607:   return(0);
    608: }

    610: /*@
    611:   PetscDSGetNumFields - Returns the number of fields in the DS

    613:   Not collective

    615:   Input Parameter:
    616: . prob - The PetscDS object

    618:   Output Parameter:
    619: . Nf - The number of fields

    621:   Level: beginner

    623: .seealso: PetscDSGetSpatialDimension(), PetscDSCreate()
    624: @*/
    625: PetscErrorCode PetscDSGetNumFields(PetscDS prob, PetscInt *Nf)
    626: {
    630:   *Nf = prob->Nf;
    631:   return(0);
    632: }

    634: /*@
    635:   PetscDSGetSpatialDimension - Returns the spatial dimension of the DS, meaning the topological dimension of the discretizations

    637:   Not collective

    639:   Input Parameter:
    640: . prob - The PetscDS object

    642:   Output Parameter:
    643: . dim - The spatial dimension

    645:   Level: beginner

    647: .seealso: PetscDSGetCoordinateDimension(), PetscDSGetNumFields(), PetscDSCreate()
    648: @*/
    649: PetscErrorCode PetscDSGetSpatialDimension(PetscDS prob, PetscInt *dim)
    650: {

    656:   *dim = 0;
    657:   if (prob->Nf) {
    658:     PetscObject  obj;
    659:     PetscClassId id;

    661:     PetscDSGetDiscretization(prob, 0, &obj);
    662:     PetscObjectGetClassId(obj, &id);
    663:     if (id == PETSCFE_CLASSID)      {PetscFEGetSpatialDimension((PetscFE) obj, dim);}
    664:     else if (id == PETSCFV_CLASSID) {PetscFVGetSpatialDimension((PetscFV) obj, dim);}
    665:     else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", 0);
    666:   }
    667:   return(0);
    668: }

    670: /*@
    671:   PetscDSGetCoordinateDimension - Returns the coordinate dimension of the DS, meaning the dimension of the space into which the discretiaztions are embedded

    673:   Not collective

    675:   Input Parameter:
    676: . prob - The PetscDS object

    678:   Output Parameter:
    679: . dimEmbed - The coordinate dimension

    681:   Level: beginner

    683: .seealso: PetscDSSetCoordinateDimension(), PetscDSGetSpatialDimension(), PetscDSGetNumFields(), PetscDSCreate()
    684: @*/
    685: PetscErrorCode PetscDSGetCoordinateDimension(PetscDS prob, PetscInt *dimEmbed)
    686: {
    690:   if (prob->dimEmbed < 0) SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONGSTATE, "No coordinate dimension set for this DS");
    691:   *dimEmbed = prob->dimEmbed;
    692:   return(0);
    693: }

    695: /*@
    696:   PetscDSSetCoordinateDimension - Set the coordinate dimension of the DS, meaning the dimension of the space into which the discretiaztions are embedded

    698:   Logically collective on prob

    700:   Input Parameters:
    701: + prob - The PetscDS object
    702: - dimEmbed - The coordinate dimension

    704:   Level: beginner

    706: .seealso: PetscDSGetCoordinateDimension(), PetscDSGetSpatialDimension(), PetscDSGetNumFields(), PetscDSCreate()
    707: @*/
    708: PetscErrorCode PetscDSSetCoordinateDimension(PetscDS prob, PetscInt dimEmbed)
    709: {
    712:   if (dimEmbed < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate dimension must be non-negative, not %D", dimEmbed);
    713:   prob->dimEmbed = dimEmbed;
    714:   return(0);
    715: }

    717: /*@
    718:   PetscDSGetHybrid - Returns the flag for a hybrid (cohesive) cell

    720:   Not collective

    722:   Input Parameter:
    723: . prob - The PetscDS object

    725:   Output Parameter:
    726: . isHybrid - The flag

    728:   Level: developer

    730: .seealso: PetscDSSetHybrid(), PetscDSCreate()
    731: @*/
    732: PetscErrorCode PetscDSGetHybrid(PetscDS prob, PetscBool *isHybrid)
    733: {
    737:   *isHybrid = prob->isHybrid;
    738:   return(0);
    739: }

    741: /*@
    742:   PetscDSSetHybrid - Set the flag for a hybrid (cohesive) cell

    744:   Not collective

    746:   Input Parameters:
    747: + prob - The PetscDS object
    748: - isHybrid - The flag

    750:   Level: developer

    752: .seealso: PetscDSGetHybrid(), PetscDSCreate()
    753: @*/
    754: PetscErrorCode PetscDSSetHybrid(PetscDS prob, PetscBool isHybrid)
    755: {
    758:   prob->isHybrid = isHybrid;
    759:   return(0);
    760: }

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

    765:   Not collective

    767:   Input Parameter:
    768: . prob - The PetscDS object

    770:   Output Parameter:
    771: . dim - The total problem dimension

    773:   Level: beginner

    775: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    776: @*/
    777: PetscErrorCode PetscDSGetTotalDimension(PetscDS prob, PetscInt *dim)
    778: {

    783:   PetscDSSetUp(prob);
    785:   *dim = prob->totDim;
    786:   return(0);
    787: }

    789: /*@
    790:   PetscDSGetTotalComponents - Returns the total number of components in this system

    792:   Not collective

    794:   Input Parameter:
    795: . prob - The PetscDS object

    797:   Output Parameter:
    798: . dim - The total number of components

    800:   Level: beginner

    802: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    803: @*/
    804: PetscErrorCode PetscDSGetTotalComponents(PetscDS prob, PetscInt *Nc)
    805: {

    810:   PetscDSSetUp(prob);
    812:   *Nc = prob->totComp;
    813:   return(0);
    814: }

    816: /*@
    817:   PetscDSGetDiscretization - Returns the discretization object for the given field

    819:   Not collective

    821:   Input Parameters:
    822: + prob - The PetscDS object
    823: - f - The field number

    825:   Output Parameter:
    826: . disc - The discretization object

    828:   Level: beginner

    830: .seealso: PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    831: @*/
    832: PetscErrorCode PetscDSGetDiscretization(PetscDS prob, PetscInt f, PetscObject *disc)
    833: {
    837:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    838:   *disc = prob->disc[f];
    839:   return(0);
    840: }

    842: /*@
    843:   PetscDSSetDiscretization - Sets the discretization object for the given field

    845:   Not collective

    847:   Input Parameters:
    848: + prob - The PetscDS object
    849: . f - The field number
    850: - disc - The discretization object

    852:   Level: beginner

    854: .seealso: PetscDSGetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    855: @*/
    856: PetscErrorCode PetscDSSetDiscretization(PetscDS prob, PetscInt f, PetscObject disc)
    857: {

    863:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    864:   PetscDSEnlarge_Static(prob, f+1);
    865:   PetscObjectDereference(prob->disc[f]);
    866:   prob->disc[f] = disc;
    867:   PetscObjectReference(disc);
    868:   {
    869:     PetscClassId id;

    871:     PetscObjectGetClassId(disc, &id);
    872:     if (id == PETSCFE_CLASSID) {
    873:       PetscDSSetImplicit(prob, f, PETSC_TRUE);
    874:     } else if (id == PETSCFV_CLASSID) {
    875:       PetscDSSetImplicit(prob, f, PETSC_FALSE);
    876:     }
    877:   }
    878:   return(0);
    879: }

    881: /*@
    882:   PetscDSAddDiscretization - Adds a discretization object

    884:   Not collective

    886:   Input Parameters:
    887: + prob - The PetscDS object
    888: - disc - The boundary discretization object

    890:   Level: beginner

    892: .seealso: PetscDSGetDiscretization(), PetscDSSetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    893: @*/
    894: PetscErrorCode PetscDSAddDiscretization(PetscDS prob, PetscObject disc)
    895: {

    899:   PetscDSSetDiscretization(prob, prob->Nf, disc);
    900:   return(0);
    901: }

    903: /*@
    904:   PetscDSGetImplicit - Returns the flag for implicit solve for this field. This is just a guide for IMEX

    906:   Not collective

    908:   Input Parameters:
    909: + prob - The PetscDS object
    910: - f - The field number

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

    915:   Level: developer

    917: .seealso: PetscDSSetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    918: @*/
    919: PetscErrorCode PetscDSGetImplicit(PetscDS prob, PetscInt f, PetscBool *implicit)
    920: {
    924:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    925:   *implicit = prob->implicit[f];
    926:   return(0);
    927: }

    929: /*@
    930:   PetscDSSetImplicit - Set the flag for implicit solve for this field. This is just a guide for IMEX

    932:   Not collective

    934:   Input Parameters:
    935: + prob - The PetscDS object
    936: . f - The field number
    937: - implicit - The flag indicating what kind of solve to use for this field

    939:   Level: developer

    941: .seealso: PetscDSGetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    942: @*/
    943: PetscErrorCode PetscDSSetImplicit(PetscDS prob, PetscInt f, PetscBool implicit)
    944: {
    947:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    948:   prob->implicit[f] = implicit;
    949:   return(0);
    950: }

    952: PetscErrorCode PetscDSGetObjective(PetscDS prob, PetscInt f,
    953:                                    void (**obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    954:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    955:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    956:                                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
    957: {
    961:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    962:   *obj = prob->obj[f];
    963:   return(0);
    964: }

    966: PetscErrorCode PetscDSSetObjective(PetscDS prob, PetscInt f,
    967:                                    void (*obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    968:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    969:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    970:                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
    971: {

    977:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    978:   PetscDSEnlarge_Static(prob, f+1);
    979:   prob->obj[f] = obj;
    980:   return(0);
    981: }

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

    986:   Not collective

    988:   Input Parameters:
    989: + prob - The PetscDS
    990: - f    - The test field number

    992:   Output Parameters:
    993: + f0 - integrand for the test function term
    994: - f1 - integrand for the test function gradient term

    996:   Note: We are using a first order FEM model for the weak form:

    998:   \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)

    1000: The calling sequence for the callbacks f0 and f1 is given by:

    1002: $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1003: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1004: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1005: $    PetscReal t, const PetscReal x[], PetscScalar f0[])

    1007: + dim - the spatial dimension
    1008: . Nf - the number of fields
    1009: . uOff - the offset into u[] and u_t[] for each field
    1010: . uOff_x - the offset into u_x[] for each field
    1011: . u - each field evaluated at the current point
    1012: . u_t - the time derivative of each field evaluated at the current point
    1013: . u_x - the gradient of each field evaluated at the current point
    1014: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1015: . aOff_x - the offset into a_x[] for each auxiliary field
    1016: . a - each auxiliary field evaluated at the current point
    1017: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1018: . a_x - the gradient of auxiliary each field evaluated at the current point
    1019: . t - current time
    1020: . x - coordinates of the current point
    1021: . numConstants - number of constant parameters
    1022: . constants - constant parameters
    1023: - f0 - output values at the current point

    1025:   Level: intermediate

    1027: .seealso: PetscDSSetResidual()
    1028: @*/
    1029: PetscErrorCode PetscDSGetResidual(PetscDS prob, PetscInt f,
    1030:                                   void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1031:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1032:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1033:                                               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
    1034:                                   void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1035:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1036:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1037:                                               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
    1038: {
    1041:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    1044:   return(0);
    1045: }

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

    1050:   Not collective

    1052:   Input Parameters:
    1053: + prob - The PetscDS
    1054: . f    - The test field number
    1055: . f0 - integrand for the test function term
    1056: - f1 - integrand for the test function gradient term

    1058:   Note: We are using a first order FEM model for the weak form:

    1060:   \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)

    1062: The calling sequence for the callbacks f0 and f1 is given by:

    1064: $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1065: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1066: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1067: $    PetscReal t, const PetscReal x[], PetscScalar f0[])

    1069: + dim - the spatial dimension
    1070: . Nf - the number of fields
    1071: . uOff - the offset into u[] and u_t[] for each field
    1072: . uOff_x - the offset into u_x[] for each field
    1073: . u - each field evaluated at the current point
    1074: . u_t - the time derivative of each field evaluated at the current point
    1075: . u_x - the gradient of each field evaluated at the current point
    1076: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1077: . aOff_x - the offset into a_x[] for each auxiliary field
    1078: . a - each auxiliary field evaluated at the current point
    1079: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1080: . a_x - the gradient of auxiliary each field evaluated at the current point
    1081: . t - current time
    1082: . x - coordinates of the current point
    1083: . numConstants - number of constant parameters
    1084: . constants - constant parameters
    1085: - f0 - output values at the current point

    1087:   Level: intermediate

    1089: .seealso: PetscDSGetResidual()
    1090: @*/
    1091: PetscErrorCode PetscDSSetResidual(PetscDS prob, PetscInt f,
    1092:                                   void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1093:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1094:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1095:                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
    1096:                                   void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1097:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1098:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1099:                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
    1100: {

    1107:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1108:   PetscDSEnlarge_Static(prob, f+1);
    1109:   prob->f[f*2+0] = f0;
    1110:   prob->f[f*2+1] = f1;
    1111:   return(0);
    1112: }

    1114: /*@C
    1115:   PetscDSHasJacobian - Signals that Jacobian functions have been set

    1117:   Not collective

    1119:   Input Parameter:
    1120: . prob - The PetscDS

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

    1125:   Level: intermediate

    1127: .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
    1128: @*/
    1129: PetscErrorCode PetscDSHasJacobian(PetscDS prob, PetscBool *hasJac)
    1130: {
    1131:   PetscInt f, g, h;

    1135:   *hasJac = PETSC_FALSE;
    1136:   for (f = 0; f < prob->Nf; ++f) {
    1137:     for (g = 0; g < prob->Nf; ++g) {
    1138:       for (h = 0; h < 4; ++h) {
    1139:         if (prob->g[(f*prob->Nf + g)*4+h]) *hasJac = PETSC_TRUE;
    1140:       }
    1141:     }
    1142:   }
    1143:   return(0);
    1144: }

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

    1149:   Not collective

    1151:   Input Parameters:
    1152: + prob - The PetscDS
    1153: . f    - The test field number
    1154: - g    - The field number

    1156:   Output Parameters:
    1157: + g0 - integrand for the test and basis function term
    1158: . g1 - integrand for the test function and basis function gradient term
    1159: . g2 - integrand for the test function gradient and basis function term
    1160: - g3 - integrand for the test function gradient and basis function gradient term

    1162:   Note: We are using a first order FEM model for the weak form:

    1164:   \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 + \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

    1166: The calling sequence for the callbacks g0, g1, g2 and g3 is given by:

    1168: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1169: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1170: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1171: $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])

    1173: + dim - the spatial dimension
    1174: . Nf - the number of fields
    1175: . uOff - the offset into u[] and u_t[] for each field
    1176: . uOff_x - the offset into u_x[] for each field
    1177: . u - each field evaluated at the current point
    1178: . u_t - the time derivative of each field evaluated at the current point
    1179: . u_x - the gradient of each field evaluated at the current point
    1180: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1181: . aOff_x - the offset into a_x[] for each auxiliary field
    1182: . a - each auxiliary field evaluated at the current point
    1183: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1184: . a_x - the gradient of auxiliary each field evaluated at the current point
    1185: . t - current time
    1186: . u_tShift - the multiplier a for dF/dU_t
    1187: . x - coordinates of the current point
    1188: . numConstants - number of constant parameters
    1189: . constants - constant parameters
    1190: - g0 - output values at the current point

    1192:   Level: intermediate

    1194: .seealso: PetscDSSetJacobian()
    1195: @*/
    1196: PetscErrorCode PetscDSGetJacobian(PetscDS prob, PetscInt f, PetscInt g,
    1197:                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1198:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1199:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1200:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1201:                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1202:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1203:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1204:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1205:                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1206:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1207:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1208:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1209:                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1210:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1211:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1212:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1213: {
    1216:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    1217:   if ((g < 0) || (g >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, prob->Nf);
    1222:   return(0);
    1223: }

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

    1228:   Not collective

    1230:   Input Parameters:
    1231: + prob - The PetscDS
    1232: . f    - The test field number
    1233: . g    - The field number
    1234: . g0 - integrand for the test and basis function term
    1235: . g1 - integrand for the test function and basis function gradient term
    1236: . g2 - integrand for the test function gradient and basis function term
    1237: - g3 - integrand for the test function gradient and basis function gradient term

    1239:   Note: We are using a first order FEM model for the weak form:

    1241:   \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 + \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

    1243: The calling sequence for the callbacks g0, g1, g2 and g3 is given by:

    1245: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1246: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1247: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1248: $    PetscReal t, const PetscReal x[], PetscScalar g0[])

    1250: + dim - the spatial dimension
    1251: . Nf - the number of fields
    1252: . uOff - the offset into u[] and u_t[] for each field
    1253: . uOff_x - the offset into u_x[] for each field
    1254: . u - each field evaluated at the current point
    1255: . u_t - the time derivative of each field evaluated at the current point
    1256: . u_x - the gradient of each field evaluated at the current point
    1257: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1258: . aOff_x - the offset into a_x[] for each auxiliary field
    1259: . a - each auxiliary field evaluated at the current point
    1260: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1261: . a_x - the gradient of auxiliary each field evaluated at the current point
    1262: . t - current time
    1263: . u_tShift - the multiplier a for dF/dU_t
    1264: . x - coordinates of the current point
    1265: . numConstants - number of constant parameters
    1266: . constants - constant parameters
    1267: - g0 - output values at the current point

    1269:   Level: intermediate

    1271: .seealso: PetscDSGetJacobian()
    1272: @*/
    1273: PetscErrorCode PetscDSSetJacobian(PetscDS prob, PetscInt f, PetscInt g,
    1274:                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1275:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1276:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1277:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1278:                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1279:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1280:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1281:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1282:                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1283:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1284:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1285:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1286:                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1287:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1288:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1289:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1290: {

    1299:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1300:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    1301:   PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);
    1302:   prob->g[(f*prob->Nf + g)*4+0] = g0;
    1303:   prob->g[(f*prob->Nf + g)*4+1] = g1;
    1304:   prob->g[(f*prob->Nf + g)*4+2] = g2;
    1305:   prob->g[(f*prob->Nf + g)*4+3] = g3;
    1306:   return(0);
    1307: }

    1309: /*@C
    1310:   PetscDSUseJacobianPreconditioner - Whether to construct a Jacobian preconditioner

    1312:   Not collective

    1314:   Input Parameters:
    1315: + prob - The PetscDS
    1316: - useJacPre - flag that enables construction of a Jacobian preconditioner

    1318:   Level: intermediate

    1320: .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
    1321: @*/
    1322: PetscErrorCode PetscDSUseJacobianPreconditioner(PetscDS prob, PetscBool useJacPre)
    1323: {
    1326:   prob->useJacPre = useJacPre;
    1327:   return(0);
    1328: }

    1330: /*@C
    1331:   PetscDSHasJacobianPreconditioner - Signals that a Jacobian preconditioner matrix has been set

    1333:   Not collective

    1335:   Input Parameter:
    1336: . prob - The PetscDS

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

    1341:   Level: intermediate

    1343: .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
    1344: @*/
    1345: PetscErrorCode PetscDSHasJacobianPreconditioner(PetscDS prob, PetscBool *hasJacPre)
    1346: {
    1347:   PetscInt f, g, h;

    1351:   *hasJacPre = PETSC_FALSE;
    1352:   if (!prob->useJacPre) return(0);
    1353:   for (f = 0; f < prob->Nf; ++f) {
    1354:     for (g = 0; g < prob->Nf; ++g) {
    1355:       for (h = 0; h < 4; ++h) {
    1356:         if (prob->gp[(f*prob->Nf + g)*4+h]) *hasJacPre = PETSC_TRUE;
    1357:       }
    1358:     }
    1359:   }
    1360:   return(0);
    1361: }

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

    1366:   Not collective

    1368:   Input Parameters:
    1369: + prob - The PetscDS
    1370: . f    - The test field number
    1371: - g    - The field number

    1373:   Output Parameters:
    1374: + g0 - integrand for the test and basis function term
    1375: . g1 - integrand for the test function and basis function gradient term
    1376: . g2 - integrand for the test function gradient and basis function term
    1377: - g3 - integrand for the test function gradient and basis function gradient term

    1379:   Note: We are using a first order FEM model for the weak form:

    1381:   \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 + \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

    1383: The calling sequence for the callbacks g0, g1, g2 and g3 is given by:

    1385: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1386: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1387: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1388: $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])

    1390: + dim - the spatial dimension
    1391: . Nf - the number of fields
    1392: . uOff - the offset into u[] and u_t[] for each field
    1393: . uOff_x - the offset into u_x[] for each field
    1394: . u - each field evaluated at the current point
    1395: . u_t - the time derivative of each field evaluated at the current point
    1396: . u_x - the gradient of each field evaluated at the current point
    1397: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1398: . aOff_x - the offset into a_x[] for each auxiliary field
    1399: . a - each auxiliary field evaluated at the current point
    1400: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1401: . a_x - the gradient of auxiliary each field evaluated at the current point
    1402: . t - current time
    1403: . u_tShift - the multiplier a for dF/dU_t
    1404: . x - coordinates of the current point
    1405: . numConstants - number of constant parameters
    1406: . constants - constant parameters
    1407: - g0 - output values at the current point

    1409:   Level: intermediate

    1411: .seealso: PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
    1412: @*/
    1413: PetscErrorCode PetscDSGetJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
    1414:                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1415:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1416:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1417:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1418:                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1419:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1420:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1421:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1422:                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1423:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1424:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1425:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1426:                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1427:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1428:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1429:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1430: {
    1433:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    1434:   if ((g < 0) || (g >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, prob->Nf);
    1439:   return(0);
    1440: }

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

    1445:   Not collective

    1447:   Input Parameters:
    1448: + prob - The PetscDS
    1449: . f    - The test field number
    1450: . g    - The field number
    1451: . g0 - integrand for the test and basis function term
    1452: . g1 - integrand for the test function and basis function gradient term
    1453: . g2 - integrand for the test function gradient and basis function term
    1454: - g3 - integrand for the test function gradient and basis function gradient term

    1456:   Note: We are using a first order FEM model for the weak form:

    1458:   \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 + \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

    1460: The calling sequence for the callbacks g0, g1, g2 and g3 is given by:

    1462: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1463: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1464: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1465: $    PetscReal t, const PetscReal x[], PetscScalar g0[])

    1467: + dim - the spatial dimension
    1468: . Nf - the number of fields
    1469: . uOff - the offset into u[] and u_t[] for each field
    1470: . uOff_x - the offset into u_x[] for each field
    1471: . u - each field evaluated at the current point
    1472: . u_t - the time derivative of each field evaluated at the current point
    1473: . u_x - the gradient of each field evaluated at the current point
    1474: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1475: . aOff_x - the offset into a_x[] for each auxiliary field
    1476: . a - each auxiliary field evaluated at the current point
    1477: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1478: . a_x - the gradient of auxiliary each field evaluated at the current point
    1479: . t - current time
    1480: . u_tShift - the multiplier a for dF/dU_t
    1481: . x - coordinates of the current point
    1482: . numConstants - number of constant parameters
    1483: . constants - constant parameters
    1484: - g0 - output values at the current point

    1486:   Level: intermediate

    1488: .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobian()
    1489: @*/
    1490: PetscErrorCode PetscDSSetJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
    1491:                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1492:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1493:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1494:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1495:                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1496:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1497:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1498:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1499:                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1500:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1501:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1502:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1503:                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1504:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1505:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1506:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1507: {

    1516:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1517:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    1518:   PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);
    1519:   prob->gp[(f*prob->Nf + g)*4+0] = g0;
    1520:   prob->gp[(f*prob->Nf + g)*4+1] = g1;
    1521:   prob->gp[(f*prob->Nf + g)*4+2] = g2;
    1522:   prob->gp[(f*prob->Nf + g)*4+3] = g3;
    1523:   return(0);
    1524: }

    1526: /*@C
    1527:   PetscDSHasDynamicJacobian - Signals that a dynamic Jacobian, dF/du_t, has been set

    1529:   Not collective

    1531:   Input Parameter:
    1532: . prob - The PetscDS

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

    1537:   Level: intermediate

    1539: .seealso: PetscDSGetDynamicJacobian(), PetscDSSetDynamicJacobian(), PetscDSGetJacobian()
    1540: @*/
    1541: PetscErrorCode PetscDSHasDynamicJacobian(PetscDS prob, PetscBool *hasDynJac)
    1542: {
    1543:   PetscInt f, g, h;

    1547:   *hasDynJac = PETSC_FALSE;
    1548:   for (f = 0; f < prob->Nf; ++f) {
    1549:     for (g = 0; g < prob->Nf; ++g) {
    1550:       for (h = 0; h < 4; ++h) {
    1551:         if (prob->gt[(f*prob->Nf + g)*4+h]) *hasDynJac = PETSC_TRUE;
    1552:       }
    1553:     }
    1554:   }
    1555:   return(0);
    1556: }

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

    1561:   Not collective

    1563:   Input Parameters:
    1564: + prob - The PetscDS
    1565: . f    - The test field number
    1566: - g    - The field number

    1568:   Output Parameters:
    1569: + g0 - integrand for the test and basis function term
    1570: . g1 - integrand for the test function and basis function gradient term
    1571: . g2 - integrand for the test function gradient and basis function term
    1572: - g3 - integrand for the test function gradient and basis function gradient term

    1574:   Note: We are using a first order FEM model for the weak form:

    1576:   \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 + \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

    1578: The calling sequence for the callbacks g0, g1, g2 and g3 is given by:

    1580: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1581: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1582: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1583: $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])

    1585: + dim - the spatial dimension
    1586: . Nf - the number of fields
    1587: . uOff - the offset into u[] and u_t[] for each field
    1588: . uOff_x - the offset into u_x[] for each field
    1589: . u - each field evaluated at the current point
    1590: . u_t - the time derivative of each field evaluated at the current point
    1591: . u_x - the gradient of each field evaluated at the current point
    1592: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1593: . aOff_x - the offset into a_x[] for each auxiliary field
    1594: . a - each auxiliary field evaluated at the current point
    1595: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1596: . a_x - the gradient of auxiliary each field evaluated at the current point
    1597: . t - current time
    1598: . u_tShift - the multiplier a for dF/dU_t
    1599: . x - coordinates of the current point
    1600: . numConstants - number of constant parameters
    1601: . constants - constant parameters
    1602: - g0 - output values at the current point

    1604:   Level: intermediate

    1606: .seealso: PetscDSSetJacobian()
    1607: @*/
    1608: PetscErrorCode PetscDSGetDynamicJacobian(PetscDS prob, PetscInt f, PetscInt g,
    1609:                                          void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1610:                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1611:                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1612:                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1613:                                          void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1614:                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1615:                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1616:                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1617:                                          void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1618:                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1619:                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1620:                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1621:                                          void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1622:                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1623:                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1624:                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1625: {
    1628:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    1629:   if ((g < 0) || (g >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, prob->Nf);
    1634:   return(0);
    1635: }

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

    1640:   Not collective

    1642:   Input Parameters:
    1643: + prob - The PetscDS
    1644: . f    - The test field number
    1645: . g    - The field number
    1646: . g0 - integrand for the test and basis function term
    1647: . g1 - integrand for the test function and basis function gradient term
    1648: . g2 - integrand for the test function gradient and basis function term
    1649: - g3 - integrand for the test function gradient and basis function gradient term

    1651:   Note: We are using a first order FEM model for the weak form:

    1653:   \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 + \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

    1655: The calling sequence for the callbacks g0, g1, g2 and g3 is given by:

    1657: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1658: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1659: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1660: $    PetscReal t, const PetscReal x[], PetscScalar g0[])

    1662: + dim - the spatial dimension
    1663: . Nf - the number of fields
    1664: . uOff - the offset into u[] and u_t[] for each field
    1665: . uOff_x - the offset into u_x[] for each field
    1666: . u - each field evaluated at the current point
    1667: . u_t - the time derivative of each field evaluated at the current point
    1668: . u_x - the gradient of each field evaluated at the current point
    1669: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1670: . aOff_x - the offset into a_x[] for each auxiliary field
    1671: . a - each auxiliary field evaluated at the current point
    1672: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1673: . a_x - the gradient of auxiliary each field evaluated at the current point
    1674: . t - current time
    1675: . u_tShift - the multiplier a for dF/dU_t
    1676: . x - coordinates of the current point
    1677: . numConstants - number of constant parameters
    1678: . constants - constant parameters
    1679: - g0 - output values at the current point

    1681:   Level: intermediate

    1683: .seealso: PetscDSGetJacobian()
    1684: @*/
    1685: PetscErrorCode PetscDSSetDynamicJacobian(PetscDS prob, PetscInt f, PetscInt g,
    1686:                                          void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1687:                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1688:                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1689:                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1690:                                          void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1691:                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1692:                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1693:                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1694:                                          void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1695:                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1696:                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1697:                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1698:                                          void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1699:                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1700:                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1701:                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1702: {

    1711:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1712:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    1713:   PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);
    1714:   prob->gt[(f*prob->Nf + g)*4+0] = g0;
    1715:   prob->gt[(f*prob->Nf + g)*4+1] = g1;
    1716:   prob->gt[(f*prob->Nf + g)*4+2] = g2;
    1717:   prob->gt[(f*prob->Nf + g)*4+3] = g3;
    1718:   return(0);
    1719: }

    1721: /*@C
    1722:   PetscDSGetRiemannSolver - Returns the Riemann solver for the given field

    1724:   Not collective

    1726:   Input Arguments:
    1727: + prob - The PetscDS object
    1728: - f    - The field number

    1730:   Output Argument:
    1731: . r    - Riemann solver

    1733:   Calling sequence for r:

    1735: $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)

    1737: + dim  - The spatial dimension
    1738: . Nf   - The number of fields
    1739: . x    - The coordinates at a point on the interface
    1740: . n    - The normal vector to the interface
    1741: . uL   - The state vector to the left of the interface
    1742: . uR   - The state vector to the right of the interface
    1743: . flux - output array of flux through the interface
    1744: . numConstants - number of constant parameters
    1745: . constants - constant parameters
    1746: - ctx  - optional user context

    1748:   Level: intermediate

    1750: .seealso: PetscDSSetRiemannSolver()
    1751: @*/
    1752: PetscErrorCode PetscDSGetRiemannSolver(PetscDS prob, PetscInt f,
    1753:                                        void (**r)(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscInt numConstants, const PetscScalar constants[], PetscScalar flux[], void *ctx))
    1754: {
    1757:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    1759:   *r = prob->r[f];
    1760:   return(0);
    1761: }

    1763: /*@C
    1764:   PetscDSSetRiemannSolver - Sets the Riemann solver for the given field

    1766:   Not collective

    1768:   Input Arguments:
    1769: + prob - The PetscDS object
    1770: . f    - The field number
    1771: - r    - Riemann solver

    1773:   Calling sequence for r:

    1775: $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)

    1777: + dim  - The spatial dimension
    1778: . Nf   - The number of fields
    1779: . x    - The coordinates at a point on the interface
    1780: . n    - The normal vector to the interface
    1781: . uL   - The state vector to the left of the interface
    1782: . uR   - The state vector to the right of the interface
    1783: . flux - output array of flux through the interface
    1784: . numConstants - number of constant parameters
    1785: . constants - constant parameters
    1786: - ctx  - optional user context

    1788:   Level: intermediate

    1790: .seealso: PetscDSGetRiemannSolver()
    1791: @*/
    1792: PetscErrorCode PetscDSSetRiemannSolver(PetscDS prob, PetscInt f,
    1793:                                        void (*r)(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscInt numConstants, const PetscScalar constants[], PetscScalar flux[], void *ctx))
    1794: {

    1800:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1801:   PetscDSEnlarge_Static(prob, f+1);
    1802:   prob->r[f] = r;
    1803:   return(0);
    1804: }

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

    1809:   Not collective

    1811:   Input Parameters:
    1812: + prob - The PetscDS
    1813: - f    - The field number

    1815:   Output Parameters:
    1816: . update - update function

    1818:   Note: The calling sequence for the callback update is given by:

    1820: $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1821: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1822: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1823: $        PetscReal t, const PetscReal x[], PetscScalar uNew[])

    1825: + dim - the spatial dimension
    1826: . Nf - the number of fields
    1827: . uOff - the offset into u[] and u_t[] for each field
    1828: . uOff_x - the offset into u_x[] for each field
    1829: . u - each field evaluated at the current point
    1830: . u_t - the time derivative of each field evaluated at the current point
    1831: . u_x - the gradient of each field evaluated at the current point
    1832: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1833: . aOff_x - the offset into a_x[] for each auxiliary field
    1834: . a - each auxiliary field evaluated at the current point
    1835: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1836: . a_x - the gradient of auxiliary each field evaluated at the current point
    1837: . t - current time
    1838: . x - coordinates of the current point
    1839: - uNew - new value for field at the current point

    1841:   Level: intermediate

    1843: .seealso: PetscDSSetUpdate(), PetscDSSetResidual()
    1844: @*/
    1845: PetscErrorCode PetscDSGetUpdate(PetscDS prob, PetscInt f,
    1846:                                   void (**update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1847:                                                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1848:                                                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1849:                                                   PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
    1850: {
    1853:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    1855:   return(0);
    1856: }

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

    1861:   Not collective

    1863:   Input Parameters:
    1864: + prob   - The PetscDS
    1865: . f      - The field number
    1866: - update - update function

    1868:   Note: The calling sequence for the callback update is given by:

    1870: $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1871: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1872: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1873: $        PetscReal t, const PetscReal x[], PetscScalar uNew[])

    1875: + dim - the spatial dimension
    1876: . Nf - the number of fields
    1877: . uOff - the offset into u[] and u_t[] for each field
    1878: . uOff_x - the offset into u_x[] for each field
    1879: . u - each field evaluated at the current point
    1880: . u_t - the time derivative of each field evaluated at the current point
    1881: . u_x - the gradient of each field evaluated at the current point
    1882: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1883: . aOff_x - the offset into a_x[] for each auxiliary field
    1884: . a - each auxiliary field evaluated at the current point
    1885: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1886: . a_x - the gradient of auxiliary each field evaluated at the current point
    1887: . t - current time
    1888: . x - coordinates of the current point
    1889: - uNew - new field values at the current point

    1891:   Level: intermediate

    1893: .seealso: PetscDSGetResidual()
    1894: @*/
    1895: PetscErrorCode PetscDSSetUpdate(PetscDS prob, PetscInt f,
    1896:                                 void (*update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1897:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1898:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1899:                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
    1900: {

    1906:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1907:   PetscDSEnlarge_Static(prob, f+1);
    1908:   prob->update[f] = update;
    1909:   return(0);
    1910: }

    1912: PetscErrorCode PetscDSGetContext(PetscDS prob, PetscInt f, void **ctx)
    1913: {
    1916:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    1918:   *ctx = prob->ctx[f];
    1919:   return(0);
    1920: }

    1922: PetscErrorCode PetscDSSetContext(PetscDS prob, PetscInt f, void *ctx)
    1923: {

    1928:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1929:   PetscDSEnlarge_Static(prob, f+1);
    1930:   prob->ctx[f] = ctx;
    1931:   return(0);
    1932: }

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

    1937:   Not collective

    1939:   Input Parameters:
    1940: + prob - The PetscDS
    1941: - f    - The test field number

    1943:   Output Parameters:
    1944: + f0 - boundary integrand for the test function term
    1945: - f1 - boundary integrand for the test function gradient term

    1947:   Note: We are using a first order FEM model for the weak form:

    1949:   \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

    1951: The calling sequence for the callbacks f0 and f1 is given by:

    1953: $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1954: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1955: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1956: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])

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

    1977:   Level: intermediate

    1979: .seealso: PetscDSSetBdResidual()
    1980: @*/
    1981: PetscErrorCode PetscDSGetBdResidual(PetscDS prob, PetscInt f,
    1982:                                     void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1983:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1984:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1985:                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
    1986:                                     void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1987:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1988:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1989:                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
    1990: {
    1993:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    1996:   return(0);
    1997: }

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

    2002:   Not collective

    2004:   Input Parameters:
    2005: + prob - The PetscDS
    2006: . f    - The test field number
    2007: . f0 - boundary integrand for the test function term
    2008: - f1 - boundary integrand for the test function gradient term

    2010:   Note: We are using a first order FEM model for the weak form:

    2012:   \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

    2014: The calling sequence for the callbacks f0 and f1 is given by:

    2016: $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2017: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2018: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2019: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])

    2021: + dim - the spatial dimension
    2022: . Nf - the number of fields
    2023: . uOff - the offset into u[] and u_t[] for each field
    2024: . uOff_x - the offset into u_x[] for each field
    2025: . u - each field evaluated at the current point
    2026: . u_t - the time derivative of each field evaluated at the current point
    2027: . u_x - the gradient of each field evaluated at the current point
    2028: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2029: . aOff_x - the offset into a_x[] for each auxiliary field
    2030: . a - each auxiliary field evaluated at the current point
    2031: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2032: . a_x - the gradient of auxiliary each field evaluated at the current point
    2033: . t - current time
    2034: . x - coordinates of the current point
    2035: . n - unit normal at the current point
    2036: . numConstants - number of constant parameters
    2037: . constants - constant parameters
    2038: - f0 - output values at the current point

    2040:   Level: intermediate

    2042: .seealso: PetscDSGetBdResidual()
    2043: @*/
    2044: PetscErrorCode PetscDSSetBdResidual(PetscDS prob, PetscInt f,
    2045:                                     void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2046:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2047:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2048:                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
    2049:                                     void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2050:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2051:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2052:                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
    2053: {

    2058:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2059:   PetscDSEnlarge_Static(prob, f+1);
    2062:   return(0);
    2063: }

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

    2068:   Not collective

    2070:   Input Parameters:
    2071: + prob - The PetscDS
    2072: . f    - The test field number
    2073: - g    - The field number

    2075:   Output Parameters:
    2076: + g0 - integrand for the test and basis function term
    2077: . g1 - integrand for the test function and basis function gradient term
    2078: . g2 - integrand for the test function gradient and basis function term
    2079: - g3 - integrand for the test function gradient and basis function gradient term

    2081:   Note: We are using a first order FEM model for the weak form:

    2083:   \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 + \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

    2085: The calling sequence for the callbacks g0, g1, g2 and g3 is given by:

    2087: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2088: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2089: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2090: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])

    2092: + dim - the spatial dimension
    2093: . Nf - the number of fields
    2094: . uOff - the offset into u[] and u_t[] for each field
    2095: . uOff_x - the offset into u_x[] for each field
    2096: . u - each field evaluated at the current point
    2097: . u_t - the time derivative of each field evaluated at the current point
    2098: . u_x - the gradient of each field evaluated at the current point
    2099: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2100: . aOff_x - the offset into a_x[] for each auxiliary field
    2101: . a - each auxiliary field evaluated at the current point
    2102: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2103: . a_x - the gradient of auxiliary each field evaluated at the current point
    2104: . t - current time
    2105: . u_tShift - the multiplier a for dF/dU_t
    2106: . x - coordinates of the current point
    2107: . n - normal at the current point
    2108: . numConstants - number of constant parameters
    2109: . constants - constant parameters
    2110: - g0 - output values at the current point

    2112:   Level: intermediate

    2114: .seealso: PetscDSSetBdJacobian()
    2115: @*/
    2116: PetscErrorCode PetscDSGetBdJacobian(PetscDS prob, PetscInt f, PetscInt g,
    2117:                                     void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2118:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2119:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2120:                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    2121:                                     void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2122:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2123:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2124:                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    2125:                                     void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2126:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2127:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2128:                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    2129:                                     void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2130:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2131:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2132:                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    2133: {
    2136:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    2137:   if ((g < 0) || (g >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, prob->Nf);
    2142:   return(0);
    2143: }

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

    2148:   Not collective

    2150:   Input Parameters:
    2151: + prob - The PetscDS
    2152: . f    - The test field number
    2153: . g    - The field number
    2154: . g0 - integrand for the test and basis function term
    2155: . g1 - integrand for the test function and basis function gradient term
    2156: . g2 - integrand for the test function gradient and basis function term
    2157: - g3 - integrand for the test function gradient and basis function gradient term

    2159:   Note: We are using a first order FEM model for the weak form:

    2161:   \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 + \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

    2163: The calling sequence for the callbacks g0, g1, g2 and g3 is given by:

    2165: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2166: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2167: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2168: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])

    2170: + dim - the spatial dimension
    2171: . Nf - the number of fields
    2172: . uOff - the offset into u[] and u_t[] for each field
    2173: . uOff_x - the offset into u_x[] for each field
    2174: . u - each field evaluated at the current point
    2175: . u_t - the time derivative of each field evaluated at the current point
    2176: . u_x - the gradient of each field evaluated at the current point
    2177: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2178: . aOff_x - the offset into a_x[] for each auxiliary field
    2179: . a - each auxiliary field evaluated at the current point
    2180: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2181: . a_x - the gradient of auxiliary each field evaluated at the current point
    2182: . t - current time
    2183: . u_tShift - the multiplier a for dF/dU_t
    2184: . x - coordinates of the current point
    2185: . n - normal at the current point
    2186: . numConstants - number of constant parameters
    2187: . constants - constant parameters
    2188: - g0 - output values at the current point

    2190:   Level: intermediate

    2192: .seealso: PetscDSGetBdJacobian()
    2193: @*/
    2194: PetscErrorCode PetscDSSetBdJacobian(PetscDS prob, PetscInt f, PetscInt g,
    2195:                                     void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2196:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2197:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2198:                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    2199:                                     void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2200:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2201:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2202:                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    2203:                                     void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2204:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2205:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2206:                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    2207:                                     void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2208:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2209:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2210:                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    2211: {

    2220:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2221:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    2222:   PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);
    2223:   prob->gBd[(f*prob->Nf + g)*4+0] = g0;
    2224:   prob->gBd[(f*prob->Nf + g)*4+1] = g1;
    2225:   prob->gBd[(f*prob->Nf + g)*4+2] = g2;
    2226:   prob->gBd[(f*prob->Nf + g)*4+3] = g3;
    2227:   return(0);
    2228: }

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

    2233:   Not collective

    2235:   Input Parameters:
    2236: + prob - The PetscDS
    2237: - f    - The test field number

    2239:   Output Parameter:
    2240: + exactSol - exact solution for the test field
    2241: - exactCtx - exact solution context

    2243:   Note: The calling sequence for the solution functions is given by:

    2245: $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)

    2247: + dim - the spatial dimension
    2248: . t - current time
    2249: . x - coordinates of the current point
    2250: . Nc - the number of field components
    2251: . u - the solution field evaluated at the current point
    2252: - ctx - a user context

    2254:   Level: intermediate

    2256: .seealso: PetscDSSetExactSolution()
    2257: @*/
    2258: PetscErrorCode PetscDSGetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
    2259: {
    2262:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    2265:   return(0);
    2266: }

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

    2271:   Not collective

    2273:   Input Parameters:
    2274: + prob - The PetscDS
    2275: . f    - The test field number
    2276: . sol  - solution function for the test fields
    2277: - ctx  - solution context or NULL

    2279:   Note: The calling sequence for solution functions is given by:

    2281: $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)

    2283: + dim - the spatial dimension
    2284: . t - current time
    2285: . x - coordinates of the current point
    2286: . Nc - the number of field components
    2287: . u - the solution field evaluated at the current point
    2288: - ctx - a user context

    2290:   Level: intermediate

    2292: .seealso: PetscDSGetExactSolution()
    2293: @*/
    2294: PetscErrorCode PetscDSSetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
    2295: {

    2300:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2301:   PetscDSEnlarge_Static(prob, f+1);
    2304:   return(0);
    2305: }

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

    2310:   Not collective

    2312:   Input Parameter:
    2313: . prob - The PetscDS object

    2315:   Output Parameters:
    2316: + numConstants - The number of constants
    2317: - constants    - The array of constants, NULL if there are none

    2319:   Level: intermediate

    2321: .seealso: PetscDSSetConstants(), PetscDSCreate()
    2322: @*/
    2323: PetscErrorCode PetscDSGetConstants(PetscDS prob, PetscInt *numConstants, const PetscScalar *constants[])
    2324: {
    2329:   return(0);
    2330: }

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

    2335:   Not collective

    2337:   Input Parameters:
    2338: + prob         - The PetscDS object
    2339: . numConstants - The number of constants
    2340: - constants    - The array of constants, NULL if there are none

    2342:   Level: intermediate

    2344: .seealso: PetscDSGetConstants(), PetscDSCreate()
    2345: @*/
    2346: PetscErrorCode PetscDSSetConstants(PetscDS prob, PetscInt numConstants, PetscScalar constants[])
    2347: {

    2352:   if (numConstants != prob->numConstants) {
    2353:     PetscFree(prob->constants);
    2354:     prob->numConstants = numConstants;
    2355:     if (prob->numConstants) {
    2356:       PetscMalloc1(prob->numConstants, &prob->constants);
    2357:     } else {
    2358:       prob->constants = NULL;
    2359:     }
    2360:   }
    2361:   if (prob->numConstants) {
    2363:     PetscArraycpy(prob->constants, constants, prob->numConstants);
    2364:   }
    2365:   return(0);
    2366: }

    2368: /*@
    2369:   PetscDSGetFieldIndex - Returns the index of the given field

    2371:   Not collective

    2373:   Input Parameters:
    2374: + prob - The PetscDS object
    2375: - disc - The discretization object

    2377:   Output Parameter:
    2378: . f - The field number

    2380:   Level: beginner

    2382: .seealso: PetscGetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    2383: @*/
    2384: PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
    2385: {
    2386:   PetscInt g;

    2391:   *f = -1;
    2392:   for (g = 0; g < prob->Nf; ++g) {if (disc == prob->disc[g]) break;}
    2393:   if (g == prob->Nf) SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
    2394:   *f = g;
    2395:   return(0);
    2396: }

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

    2401:   Not collective

    2403:   Input Parameters:
    2404: + prob - The PetscDS object
    2405: - f - The field number

    2407:   Output Parameter:
    2408: . size - The size

    2410:   Level: beginner

    2412: .seealso: PetscDSGetFieldOffset(), PetscDSGetNumFields(), PetscDSCreate()
    2413: @*/
    2414: PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
    2415: {

    2421:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    2422:   PetscDSSetUp(prob);
    2423:   *size = prob->Nb[f];
    2424:   return(0);
    2425: }

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

    2430:   Not collective

    2432:   Input Parameters:
    2433: + prob - The PetscDS object
    2434: - f - The field number

    2436:   Output Parameter:
    2437: . off - The offset

    2439:   Level: beginner

    2441: .seealso: PetscDSGetFieldSize(), PetscDSGetNumFields(), PetscDSCreate()
    2442: @*/
    2443: PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
    2444: {
    2445:   PetscInt       size, g;

    2451:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    2452:   *off = 0;
    2453:   for (g = 0; g < f; ++g) {
    2454:     PetscDSGetFieldSize(prob, g, &size);
    2455:     *off += size;
    2456:   }
    2457:   return(0);
    2458: }

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

    2463:   Not collective

    2465:   Input Parameter:
    2466: . prob - The PetscDS object

    2468:   Output Parameter:
    2469: . dimensions - The number of dimensions

    2471:   Level: beginner

    2473: .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
    2474: @*/
    2475: PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
    2476: {

    2481:   PetscDSSetUp(prob);
    2483:   *dimensions = prob->Nb;
    2484:   return(0);
    2485: }

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

    2490:   Not collective

    2492:   Input Parameter:
    2493: . prob - The PetscDS object

    2495:   Output Parameter:
    2496: . components - The number of components

    2498:   Level: beginner

    2500: .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
    2501: @*/
    2502: PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
    2503: {

    2508:   PetscDSSetUp(prob);
    2510:   *components = prob->Nc;
    2511:   return(0);
    2512: }

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

    2517:   Not collective

    2519:   Input Parameters:
    2520: + prob - The PetscDS object
    2521: - f - The field number

    2523:   Output Parameter:
    2524: . off - The offset

    2526:   Level: beginner

    2528: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    2529: @*/
    2530: PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
    2531: {
    2535:   if ((f < 0) || (f >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
    2536:   *off = prob->off[f];
    2537:   return(0);
    2538: }

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

    2543:   Not collective

    2545:   Input Parameter:
    2546: . prob - The PetscDS object

    2548:   Output Parameter:
    2549: . offsets - The offsets

    2551:   Level: beginner

    2553: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    2554: @*/
    2555: PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
    2556: {
    2560:   *offsets = prob->off;
    2561:   return(0);
    2562: }

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

    2567:   Not collective

    2569:   Input Parameter:
    2570: . prob - The PetscDS object

    2572:   Output Parameter:
    2573: . offsets - The offsets

    2575:   Level: beginner

    2577: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    2578: @*/
    2579: PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
    2580: {
    2584:   *offsets = prob->offDer;
    2585:   return(0);
    2586: }

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

    2591:   Not collective

    2593:   Input Parameter:
    2594: . prob - The PetscDS object

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

    2599:   Level: intermediate

    2601: .seealso: PetscDSCreate()
    2602: @*/
    2603: PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[])
    2604: {

    2610:   PetscDSSetUp(prob);
    2611:   *T = prob->T;
    2612:   return(0);
    2613: }

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

    2618:   Not collective

    2620:   Input Parameter:
    2621: . prob - The PetscDS object

    2623:   Output Parameter:
    2624: . Tf - The basis function and derviative tabulation on each local face at quadrature points for each and field

    2626:   Level: intermediate

    2628: .seealso: PetscDSGetTabulation(), PetscDSCreate()
    2629: @*/
    2630: PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
    2631: {

    2637:   PetscDSSetUp(prob);
    2638:   *Tf = prob->Tf;
    2639:   return(0);
    2640: }

    2642: PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
    2643: {

    2648:   PetscDSSetUp(prob);
    2652:   return(0);
    2653: }

    2655: PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar **f0, PetscScalar **f1, PetscScalar **g0, PetscScalar **g1, PetscScalar **g2, PetscScalar **g3)
    2656: {

    2661:   PetscDSSetUp(prob);
    2668:   return(0);
    2669: }

    2671: PetscErrorCode PetscDSGetWorkspace(PetscDS prob, PetscReal **x, PetscScalar **basisReal, PetscScalar **basisDerReal, PetscScalar **testReal, PetscScalar **testDerReal)
    2672: {

    2677:   PetscDSSetUp(prob);
    2683:   return(0);
    2684: }

    2686: /*@C
    2687:   PetscDSAddBoundary - Add a boundary condition to the model

    2689:   Input Parameters:
    2690: + ds          - The PetscDS object
    2691: . type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    2692: . name        - The BC name
    2693: . labelname   - The label defining constrained points
    2694: . field       - The field to constrain
    2695: . numcomps    - The number of constrained field components (0 will constrain all fields)
    2696: . comps       - An array of constrained component numbers
    2697: . bcFunc      - A pointwise function giving boundary values
    2698: . numids      - The number of DMLabel ids for constrained points
    2699: . ids         - An array of ids for constrained points
    2700: - ctx         - An optional user context for bcFunc

    2702:   Options Database Keys:
    2703: + -bc_<boundary name> <num> - Overrides the boundary ids
    2704: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    2706:   Level: developer

    2708: .seealso: PetscDSGetBoundary()
    2709: @*/
    2710: PetscErrorCode PetscDSAddBoundary(PetscDS ds, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), PetscInt numids, const PetscInt *ids, void *ctx)
    2711: {
    2712:   DSBoundary     b;

    2717:   PetscNew(&b);
    2718:   PetscStrallocpy(name, (char **) &b->name);
    2719:   PetscStrallocpy(labelname, (char **) &b->labelname);
    2720:   PetscMalloc1(numcomps, &b->comps);
    2721:   if (numcomps) {PetscArraycpy(b->comps, comps, numcomps);}
    2722:   PetscMalloc1(numids, &b->ids);
    2723:   if (numids) {PetscArraycpy(b->ids, ids, numids);}
    2724:   b->type            = type;
    2725:   b->field           = field;
    2726:   b->numcomps        = numcomps;
    2727:   b->func            = bcFunc;
    2728:   b->numids          = numids;
    2729:   b->ctx             = ctx;
    2730:   b->next            = ds->boundary;
    2731:   ds->boundary       = b;
    2732:   return(0);
    2733: }

    2735: /*@C
    2736:   PetscDSUpdateBoundary - Change a boundary condition for the model

    2738:   Input Parameters:
    2739: + ds          - The PetscDS object
    2740: . bd          - The boundary condition number
    2741: . type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    2742: . name        - The BC name
    2743: . labelname   - The label defining constrained points
    2744: . field       - The field to constrain
    2745: . numcomps    - The number of constrained field components
    2746: . comps       - An array of constrained component numbers
    2747: . bcFunc      - A pointwise function giving boundary values
    2748: . numids      - The number of DMLabel ids for constrained points
    2749: . ids         - An array of ids for constrained points
    2750: - ctx         - An optional user context for bcFunc

    2752:   Note: The boundary condition number is the order in which it was registered. The user can get the number of boundary conditions from PetscDSGetNumBoundary().

    2754:   Level: developer

    2756: .seealso: PetscDSAddBoundary(), PetscDSGetBoundary(), PetscDSGetNumBoundary()
    2757: @*/
    2758: PetscErrorCode PetscDSUpdateBoundary(PetscDS ds, PetscInt bd, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), PetscInt numids, const PetscInt *ids, void *ctx)
    2759: {
    2760:   DSBoundary     b = ds->boundary;
    2761:   PetscInt       n = 0;

    2766:   while (b) {
    2767:     if (n == bd) break;
    2768:     b = b->next;
    2769:     ++n;
    2770:   }
    2771:   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
    2772:   if (name) {
    2773:     PetscFree(b->name);
    2774:     PetscStrallocpy(name, (char **) &b->name);
    2775:   }
    2776:   if (labelname) {
    2777:     PetscFree(b->labelname);
    2778:     PetscStrallocpy(labelname, (char **) &b->labelname);
    2779:   }
    2780:   if (numcomps >= 0 && numcomps != b->numcomps) {
    2781:     b->numcomps = numcomps;
    2782:     PetscFree(b->comps);
    2783:     PetscMalloc1(numcomps, &b->comps);
    2784:     if (numcomps) {PetscArraycpy(b->comps, comps, numcomps);}
    2785:   }
    2786:   if (numids >= 0 && numids != b->numids) {
    2787:     b->numids = numids;
    2788:     PetscFree(b->ids);
    2789:     PetscMalloc1(numids, &b->ids);
    2790:     if (numids) {PetscArraycpy(b->ids, ids, numids);}
    2791:   }
    2792:   b->type = type;
    2793:   if (field >= 0) {b->field  = field;}
    2794:   if (bcFunc)     {b->func   = bcFunc;}
    2795:   if (ctx)        {b->ctx    = ctx;}
    2796:   return(0);
    2797: }

    2799: /*@
    2800:   PetscDSGetNumBoundary - Get the number of registered BC

    2802:   Input Parameters:
    2803: . ds - The PetscDS object

    2805:   Output Parameters:
    2806: . numBd - The number of BC

    2808:   Level: intermediate

    2810: .seealso: PetscDSAddBoundary(), PetscDSGetBoundary()
    2811: @*/
    2812: PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
    2813: {
    2814:   DSBoundary b = ds->boundary;

    2819:   *numBd = 0;
    2820:   while (b) {++(*numBd); b = b->next;}
    2821:   return(0);
    2822: }

    2824: /*@C
    2825:   PetscDSGetBoundary - Gets a boundary condition to the model

    2827:   Input Parameters:
    2828: + ds          - The PetscDS object
    2829: - bd          - The BC number

    2831:   Output Parameters:
    2832: + type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    2833: . name        - The BC name
    2834: . labelname   - The label defining constrained points
    2835: . field       - The field to constrain
    2836: . numcomps    - The number of constrained field components
    2837: . comps       - An array of constrained component numbers
    2838: . bcFunc      - A pointwise function giving boundary values
    2839: . numids      - The number of DMLabel ids for constrained points
    2840: . ids         - An array of ids for constrained points
    2841: - ctx         - An optional user context for bcFunc

    2843:   Options Database Keys:
    2844: + -bc_<boundary name> <num> - Overrides the boundary ids
    2845: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    2847:   Level: developer

    2849: .seealso: PetscDSAddBoundary()
    2850: @*/
    2851: PetscErrorCode PetscDSGetBoundary(PetscDS ds, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
    2852: {
    2853:   DSBoundary b    = ds->boundary;
    2854:   PetscInt   n    = 0;

    2858:   while (b) {
    2859:     if (n == bd) break;
    2860:     b = b->next;
    2861:     ++n;
    2862:   }
    2863:   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
    2864:   if (type) {
    2866:     *type = b->type;
    2867:   }
    2868:   if (name) {
    2870:     *name = b->name;
    2871:   }
    2872:   if (labelname) {
    2874:     *labelname = b->labelname;
    2875:   }
    2876:   if (field) {
    2878:     *field = b->field;
    2879:   }
    2880:   if (numcomps) {
    2882:     *numcomps = b->numcomps;
    2883:   }
    2884:   if (comps) {
    2886:     *comps = b->comps;
    2887:   }
    2888:   if (func) {
    2890:     *func = b->func;
    2891:   }
    2892:   if (numids) {
    2894:     *numids = b->numids;
    2895:   }
    2896:   if (ids) {
    2898:     *ids = b->ids;
    2899:   }
    2900:   if (ctx) {
    2902:     *ctx = b->ctx;
    2903:   }
    2904:   return(0);
    2905: }

    2907: /*@
    2908:   PetscDSCopyBoundary - Copy all boundary condition objects to the new problem

    2910:   Not collective

    2912:   Input Parameter:
    2913: . prob - The PetscDS object

    2915:   Output Parameter:
    2916: . newprob - The PetscDS copy

    2918:   Level: intermediate

    2920: .seealso: PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    2921: @*/
    2922: PetscErrorCode PetscDSCopyBoundary(PetscDS probA, PetscDS probB)
    2923: {
    2924:   DSBoundary     b, next, *lastnext;

    2930:   if (probA == probB) return(0);
    2931:   next = probB->boundary;
    2932:   while (next) {
    2933:     DSBoundary b = next;

    2935:     next = b->next;
    2936:     PetscFree(b->comps);
    2937:     PetscFree(b->ids);
    2938:     PetscFree(b->name);
    2939:     PetscFree(b->labelname);
    2940:     PetscFree(b);
    2941:   }
    2942:   lastnext = &(probB->boundary);
    2943:   for (b = probA->boundary; b; b = b->next) {
    2944:     DSBoundary bNew;

    2946:     PetscNew(&bNew);
    2947:     bNew->numcomps = b->numcomps;
    2948:     PetscMalloc1(bNew->numcomps, &bNew->comps);
    2949:     PetscArraycpy(bNew->comps, b->comps, bNew->numcomps);
    2950:     bNew->numids = b->numids;
    2951:     PetscMalloc1(bNew->numids, &bNew->ids);
    2952:     PetscArraycpy(bNew->ids, b->ids, bNew->numids);
    2953:     PetscStrallocpy(b->labelname,(char **) &(bNew->labelname));
    2954:     PetscStrallocpy(b->name,(char **) &(bNew->name));
    2955:     bNew->ctx   = b->ctx;
    2956:     bNew->type  = b->type;
    2957:     bNew->field = b->field;
    2958:     bNew->func  = b->func;

    2960:     *lastnext = bNew;
    2961:     lastnext = &(bNew->next);
    2962:   }
    2963:   return(0);
    2964: }

    2966: /*@C
    2967:   PetscDSSelectEquations - Copy pointwise function pointers to the new problem with different field layout

    2969:   Not collective

    2971:   Input Parameter:
    2972: + prob - The PetscDS object
    2973: . numFields - Number of new fields
    2974: - fields - Old field number for each new field

    2976:   Output Parameter:
    2977: . newprob - The PetscDS copy

    2979:   Level: intermediate

    2981: .seealso: PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    2982: @*/
    2983: PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
    2984: {
    2985:   PetscInt       Nf, Nfn, fn, gn;

    2992:   PetscDSGetNumFields(prob, &Nf);
    2993:   PetscDSGetNumFields(newprob, &Nfn);
    2994:   if (numFields > Nfn) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_SIZ, "Number of fields %D to transfer must not be greater then the total number of fields %D", numFields, Nfn);
    2995:   for (fn = 0; fn < numFields; ++fn) {
    2996:     const PetscInt   f = fields ? fields[fn] : fn;
    2997:     PetscPointFunc   obj;
    2998:     PetscPointFunc   f0, f1;
    2999:     PetscBdPointFunc f0Bd, f1Bd;
    3000:     PetscRiemannFunc r;

    3002:     if (f >= Nf) continue;
    3003:     PetscDSGetObjective(prob, f, &obj);
    3004:     PetscDSGetResidual(prob, f, &f0, &f1);
    3005:     PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd);
    3006:     PetscDSGetRiemannSolver(prob, f, &r);
    3007:     PetscDSSetObjective(newprob, fn, obj);
    3008:     PetscDSSetResidual(newprob, fn, f0, f1);
    3009:     PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd);
    3010:     PetscDSSetRiemannSolver(newprob, fn, r);
    3011:     for (gn = 0; gn < numFields; ++gn) {
    3012:       const PetscInt  g = fields ? fields[gn] : gn;
    3013:       PetscPointJac   g0, g1, g2, g3;
    3014:       PetscPointJac   g0p, g1p, g2p, g3p;
    3015:       PetscBdPointJac g0Bd, g1Bd, g2Bd, g3Bd;

    3017:       if (g >= Nf) continue;
    3018:       PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3);
    3019:       PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p);
    3020:       PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd);
    3021:       PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3);
    3022:       PetscDSSetJacobianPreconditioner(prob, fn, gn, g0p, g1p, g2p, g3p);
    3023:       PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd);
    3024:     }
    3025:   }
    3026:   return(0);
    3027: }

    3029: /*@
    3030:   PetscDSCopyEquations - Copy all pointwise function pointers to the new problem

    3032:   Not collective

    3034:   Input Parameter:
    3035: . prob - The PetscDS object

    3037:   Output Parameter:
    3038: . newprob - The PetscDS copy

    3040:   Level: intermediate

    3042: .seealso: PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    3043: @*/
    3044: PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
    3045: {
    3046:   PetscInt       Nf, Ng;

    3052:   PetscDSGetNumFields(prob, &Nf);
    3053:   PetscDSGetNumFields(newprob, &Ng);
    3054:   if (Nf != Ng) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %D != %D", Nf, Ng);
    3055:   PetscDSSelectEquations(prob, Nf, NULL, newprob);
    3056:   return(0);
    3057: }
    3058: /*@
    3059:   PetscDSCopyConstants - Copy all constants to the new problem

    3061:   Not collective

    3063:   Input Parameter:
    3064: . prob - The PetscDS object

    3066:   Output Parameter:
    3067: . newprob - The PetscDS copy

    3069:   Level: intermediate

    3071: .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    3072: @*/
    3073: PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
    3074: {
    3075:   PetscInt           Nc;
    3076:   const PetscScalar *constants;
    3077:   PetscErrorCode     ierr;

    3082:   PetscDSGetConstants(prob, &Nc, &constants);
    3083:   PetscDSSetConstants(newprob, Nc, (PetscScalar *) constants);
    3084:   return(0);
    3085: }

    3087: PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
    3088: {
    3089:   PetscInt       dim, Nf, f;

    3095:   if (height == 0) {*subprob = prob; return(0);}
    3096:   PetscDSGetNumFields(prob, &Nf);
    3097:   PetscDSGetSpatialDimension(prob, &dim);
    3098:   if (height > dim) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %D], not %D", dim, height);
    3099:   if (!prob->subprobs) {PetscCalloc1(dim, &prob->subprobs);}
    3100:   if (!prob->subprobs[height-1]) {
    3101:     PetscInt cdim;

    3103:     PetscDSCreate(PetscObjectComm((PetscObject) prob), &prob->subprobs[height-1]);
    3104:     PetscDSGetCoordinateDimension(prob, &cdim);
    3105:     PetscDSSetCoordinateDimension(prob->subprobs[height-1], cdim);
    3106:     for (f = 0; f < Nf; ++f) {
    3107:       PetscFE      subfe;
    3108:       PetscObject  obj;
    3109:       PetscClassId id;

    3111:       PetscDSGetDiscretization(prob, f, &obj);
    3112:       PetscObjectGetClassId(obj, &id);
    3113:       if (id == PETSCFE_CLASSID) {PetscFEGetHeightSubspace((PetscFE) obj, height, &subfe);}
    3114:       else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %d", f);
    3115:       PetscDSSetDiscretization(prob->subprobs[height-1], f, (PetscObject) subfe);
    3116:     }
    3117:   }
    3118:   *subprob = prob->subprobs[height-1];
    3119:   return(0);
    3120: }

    3122: PetscErrorCode PetscDSIsFE_Internal(PetscDS ds, PetscInt f, PetscBool *isFE)
    3123: {
    3124:   PetscObject    obj;
    3125:   PetscClassId   id;
    3126:   PetscInt       Nf;

    3132:   PetscDSGetNumFields(ds, &Nf);
    3133:   if (f >= Nf) SETERRQ2(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_SIZ, "Field %D must be in [0, %D)", f, Nf);
    3134:   PetscDSGetDiscretization(ds, f, &obj);
    3135:   PetscObjectGetClassId(obj, &id);
    3136:   if (id == PETSCFE_CLASSID) *isFE = PETSC_TRUE;
    3137:   else                       *isFE = PETSC_FALSE;
    3138:   return(0);
    3139: }

    3141: static PetscErrorCode PetscDSDestroy_Basic(PetscDS prob)
    3142: {
    3143:   PetscErrorCode      ierr;

    3146:   PetscFree(prob->data);
    3147:   return(0);
    3148: }

    3150: static PetscErrorCode PetscDSInitialize_Basic(PetscDS prob)
    3151: {
    3153:   prob->ops->setfromoptions = NULL;
    3154:   prob->ops->setup          = NULL;
    3155:   prob->ops->view           = NULL;
    3156:   prob->ops->destroy        = PetscDSDestroy_Basic;
    3157:   return(0);
    3158: }

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

    3163:   Level: intermediate

    3165: .seealso: PetscDSType, PetscDSCreate(), PetscDSSetType()
    3166: M*/

    3168: PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS prob)
    3169: {
    3170:   PetscDS_Basic *b;
    3171:   PetscErrorCode      ierr;

    3175:   PetscNewLog(prob, &b);
    3176:   prob->data = b;

    3178:   PetscDSInitialize_Basic(prob);
    3179:   return(0);
    3180: }