Date: 2022-03-04T17:38:43+00:00

Actual source code: dtds.c

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

      3: PetscClassId PETSCDS_CLASSID = 0;

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

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

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

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

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

     24:   Not Collective

     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, " %D-jet", prob->jetDegree[f]);
    180:     PetscViewerASCIIPrintf(viewer, "\n");
    181:     PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
    182:     PetscViewerASCIIPushTab(viewer);
    183:     if (id == PETSCFE_CLASSID)      {PetscFEView((PetscFE) obj, viewer);}
    184:     else if (id == PETSCFV_CLASSID) {PetscFVView((PetscFV) obj, viewer);}
    185:     PetscViewerASCIIPopTab(viewer);

    187:     for (b = prob->boundary; b; b = b->next) {
    188:       char     *name;
    189:       PetscInt  c, i;

    191:       if (b->field != f) continue;
    192:       PetscViewerASCIIPushTab(viewer);
    193:       PetscViewerASCIIPrintf(viewer, "Boundary %s (%s) %s\n", b->name, b->lname, DMBoundaryConditionTypes[b->type]);
    194:       if (!b->Nc) {
    195:         PetscViewerASCIIPrintf(viewer, "  all components\n");
    196:       } else {
    197:         PetscViewerASCIIPrintf(viewer, "  components: ");
    198:         PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
    199:         for (c = 0; c < b->Nc; ++c) {
    200:           if (c > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
    201:           PetscViewerASCIIPrintf(viewer, "%D", b->comps[c]);
    202:         }
    203:         PetscViewerASCIIPrintf(viewer, "\n");
    204:         PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
    205:       }
    206:       PetscViewerASCIIPrintf(viewer, "  values: ");
    207:       PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);
    208:       for (i = 0; i < b->Nv; ++i) {
    209:         if (i > 0) {PetscViewerASCIIPrintf(viewer, ", ");}
    210:         PetscViewerASCIIPrintf(viewer, "%D", b->values[i]);
    211:       }
    212:       PetscViewerASCIIPrintf(viewer, "\n");
    213:       PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);
    214:       if (b->func) {
    215:         PetscDLAddr(b->func, &name);
    216:         if (name) {PetscViewerASCIIPrintf(viewer, "  func: %s\n", name);}
    217:         else      {PetscViewerASCIIPrintf(viewer, "  func: %p\n", b->func);}
    218:         PetscFree(name);
    219:       }
    220:       if (b->func_t) {
    221:         PetscDLAddr(b->func_t, &name);
    222:         if (name) {PetscViewerASCIIPrintf(viewer, "  func_t: %s\n", name);}
    223:         else      {PetscViewerASCIIPrintf(viewer, "  func_t: %p\n", b->func_t);}
    224:         PetscFree(name);
    225:       }
    226:       PetscWeakFormView(b->wf, viewer);
    227:       PetscViewerASCIIPopTab(viewer);
    228:     }
    229:   }
    230:   PetscDSGetConstants(prob, &numConstants, &constants);
    231:   if (numConstants) {
    232:     PetscViewerASCIIPrintf(viewer, "%D constants\n", numConstants);
    233:     PetscViewerASCIIPushTab(viewer);
    234:     for (f = 0; f < numConstants; ++f) {PetscViewerASCIIPrintf(viewer, "%g\n", (double) PetscRealPart(constants[f]));}
    235:     PetscViewerASCIIPopTab(viewer);
    236:   }
    237:   PetscWeakFormView(prob->wf, viewer);
    238:   PetscViewerASCIIPopTab(viewer);
    239:   return(0);
    240: }

    242: /*@C
    243:    PetscDSViewFromOptions - View from Options

    245:    Collective on PetscDS

    247:    Input Parameters:
    248: +  A - the PetscDS object
    249: .  obj - Optional object
    250: -  name - command line option

    252:    Level: intermediate
    253: .seealso:  PetscDS, PetscDSView, PetscObjectViewFromOptions(), PetscDSCreate()
    254: @*/
    255: PetscErrorCode  PetscDSViewFromOptions(PetscDS A,PetscObject obj,const char name[])
    256: {

    261:   PetscObjectViewFromOptions((PetscObject)A,obj,name);
    262:   return(0);
    263: }

    265: /*@C
    266:   PetscDSView - Views a PetscDS

    268:   Collective on prob

    270:   Input Parameters:
    271: + prob - the PetscDS object to view
    272: - v  - the viewer

    274:   Level: developer

    276: .seealso PetscDSDestroy()
    277: @*/
    278: PetscErrorCode PetscDSView(PetscDS prob, PetscViewer v)
    279: {
    280:   PetscBool      iascii;

    285:   if (!v) {PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) prob), &v);}
    287:   PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &iascii);
    288:   if (iascii) {PetscDSView_Ascii(prob, v);}
    289:   if (prob->ops->view) {(*prob->ops->view)(prob, v);}
    290:   return(0);
    291: }

    293: /*@
    294:   PetscDSSetFromOptions - sets parameters in a PetscDS from the options database

    296:   Collective on prob

    298:   Input Parameter:
    299: . prob - the PetscDS object to set options for

    301:   Options Database:
    302: + -petscds_type <type>     : Set the DS type
    303: . -petscds_view <view opt> : View the DS
    304: . -petscds_jac_pre         : Turn formation of a separate Jacobian preconditioner on and off
    305: . -bc_<name> <ids>         : Specify a list of label ids for a boundary condition
    306: - -bc_<name>_comp <comps>  : Specify a list of field components to constrain for a boundary condition

    308:   Level: developer

    310: .seealso PetscDSView()
    311: @*/
    312: PetscErrorCode PetscDSSetFromOptions(PetscDS prob)
    313: {
    314:   DSBoundary     b;
    315:   const char    *defaultType;
    316:   char           name[256];
    317:   PetscBool      flg;

    322:   if (!((PetscObject) prob)->type_name) {
    323:     defaultType = PETSCDSBASIC;
    324:   } else {
    325:     defaultType = ((PetscObject) prob)->type_name;
    326:   }
    327:   PetscDSRegisterAll();

    329:   PetscObjectOptionsBegin((PetscObject) prob);
    330:   for (b = prob->boundary; b; b = b->next) {
    331:     char       optname[1024];
    332:     PetscInt   ids[1024], len = 1024;
    333:     PetscBool  flg;

    335:     PetscSNPrintf(optname, sizeof(optname), "-bc_%s", b->name);
    336:     PetscMemzero(ids, sizeof(ids));
    337:     PetscOptionsIntArray(optname, "List of boundary IDs", "", ids, &len, &flg);
    338:     if (flg) {
    339:       b->Nv = len;
    340:       PetscFree(b->values);
    341:       PetscMalloc1(len, &b->values);
    342:       PetscArraycpy(b->values, ids, len);
    343:       PetscWeakFormRewriteKeys(b->wf, b->label, len, b->values);
    344:     }
    345:     len = 1024;
    346:     PetscSNPrintf(optname, sizeof(optname), "-bc_%s_comp", b->name);
    347:     PetscMemzero(ids, sizeof(ids));
    348:     PetscOptionsIntArray(optname, "List of boundary field components", "", ids, &len, &flg);
    349:     if (flg) {
    350:       b->Nc = len;
    351:       PetscFree(b->comps);
    352:       PetscMalloc1(len, &b->comps);
    353:       PetscArraycpy(b->comps, ids, len);
    354:     }
    355:   }
    356:   PetscOptionsFList("-petscds_type", "Discrete System", "PetscDSSetType", PetscDSList, defaultType, name, 256, &flg);
    357:   if (flg) {
    358:     PetscDSSetType(prob, name);
    359:   } else if (!((PetscObject) prob)->type_name) {
    360:     PetscDSSetType(prob, defaultType);
    361:   }
    362:   PetscOptionsBool("-petscds_jac_pre", "Discrete System", "PetscDSUseJacobianPreconditioner", prob->useJacPre, &prob->useJacPre, &flg);
    363:   if (prob->ops->setfromoptions) {(*prob->ops->setfromoptions)(prob);}
    364:   /* process any options handlers added with PetscObjectAddOptionsHandler() */
    365:   PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) prob);
    366:   PetscOptionsEnd();
    367:   if (prob->Nf) {PetscDSViewFromOptions(prob, NULL, "-petscds_view");}
    368:   return(0);
    369: }

    371: /*@C
    372:   PetscDSSetUp - Construct data structures for the PetscDS

    374:   Collective on prob

    376:   Input Parameter:
    377: . prob - the PetscDS object to setup

    379:   Level: developer

    381: .seealso PetscDSView(), PetscDSDestroy()
    382: @*/
    383: PetscErrorCode PetscDSSetUp(PetscDS prob)
    384: {
    385:   const PetscInt Nf   = prob->Nf;
    386:   PetscBool      hasH = PETSC_FALSE;
    387:   PetscInt       dim, dimEmbed, NbMax = 0, NcMax = 0, NqMax = 0, NsMax = 1, f;

    392:   if (prob->setup) return(0);
    393:   /* Calculate sizes */
    394:   PetscDSGetSpatialDimension(prob, &dim);
    395:   PetscDSGetCoordinateDimension(prob, &dimEmbed);
    396:   prob->totDim = prob->totComp = 0;
    397:   PetscMalloc2(Nf,&prob->Nc,Nf,&prob->Nb);
    398:   PetscCalloc2(Nf+1,&prob->off,Nf+1,&prob->offDer);
    399:   PetscMalloc2(Nf,&prob->T,Nf,&prob->Tf);
    400:   for (f = 0; f < Nf; ++f) {
    401:     PetscObject     obj;
    402:     PetscClassId    id;
    403:     PetscQuadrature q = NULL;
    404:     PetscInt        Nq = 0, Nb, Nc;

    406:     PetscDSGetDiscretization(prob, f, &obj);
    407:     if (prob->jetDegree[f] > 1) hasH = PETSC_TRUE;
    408:     if (!obj) {
    409:       /* Empty mesh */
    410:       Nb = Nc = 0;
    411:       prob->T[f] = prob->Tf[f] = NULL;
    412:     } else {
    413:       PetscObjectGetClassId(obj, &id);
    414:       if (id == PETSCFE_CLASSID)      {
    415:         PetscFE fe = (PetscFE) obj;

    417:         PetscFEGetQuadrature(fe, &q);
    418:         PetscFEGetDimension(fe, &Nb);
    419:         PetscFEGetNumComponents(fe, &Nc);
    420:         PetscFEGetCellTabulation(fe, prob->jetDegree[f], &prob->T[f]);
    421:         PetscFEGetFaceTabulation(fe, prob->jetDegree[f], &prob->Tf[f]);
    422:       } else if (id == PETSCFV_CLASSID) {
    423:         PetscFV fv = (PetscFV) obj;

    425:         PetscFVGetQuadrature(fv, &q);
    426:         PetscFVGetNumComponents(fv, &Nc);
    427:         Nb   = Nc;
    428:         PetscFVGetCellTabulation(fv, &prob->T[f]);
    429:         /* TODO: should PetscFV also have face tabulation? Otherwise there will be a null pointer in prob->basisFace */
    430:       } else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
    431:     }
    432:     prob->Nc[f]       = Nc;
    433:     prob->Nb[f]       = Nb;
    434:     prob->off[f+1]    = Nc     + prob->off[f];
    435:     prob->offDer[f+1] = Nc*dim + prob->offDer[f];
    436:     if (q) {PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);}
    437:     NqMax          = PetscMax(NqMax, Nq);
    438:     NbMax          = PetscMax(NbMax, Nb);
    439:     NcMax          = PetscMax(NcMax, Nc);
    440:     prob->totDim  += Nb;
    441:     prob->totComp += Nc;
    442:     /* There are two faces for all fields but the cohesive field on a hybrid cell */
    443:     if (prob->isHybrid && (f < Nf-1)) prob->totDim += Nb;
    444:   }
    445:   /* Allocate works space */
    446:   NsMax = 2; /* Even non-hybrid discretizations can be used in a hybrid integration, so we need this extra workspace */
    447:   PetscMalloc3(NsMax*prob->totComp,&prob->u,NsMax*prob->totComp,&prob->u_t,NsMax*prob->totComp*dimEmbed + (hasH ? NsMax*prob->totComp*dimEmbed*dimEmbed : 0),&prob->u_x);
    448:   PetscMalloc5(dimEmbed,&prob->x,NbMax*NcMax,&prob->basisReal,NbMax*NcMax*dimEmbed,&prob->basisDerReal,NbMax*NcMax,&prob->testReal,NbMax*NcMax*dimEmbed,&prob->testDerReal);
    449:   PetscMalloc6(NsMax*NqMax*NcMax,&prob->f0,NsMax*NqMax*NcMax*dimEmbed,&prob->f1,
    450:                       NsMax*NsMax*NqMax*NcMax*NcMax,&prob->g0,NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed,&prob->g1,
    451:                       NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed,&prob->g2,NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed*dimEmbed,&prob->g3);
    452:   if (prob->ops->setup) {(*prob->ops->setup)(prob);}
    453:   prob->setup = PETSC_TRUE;
    454:   return(0);
    455: }

    457: static PetscErrorCode PetscDSDestroyStructs_Static(PetscDS prob)
    458: {

    462:   PetscFree2(prob->Nc,prob->Nb);
    463:   PetscFree2(prob->off,prob->offDer);
    464:   PetscFree2(prob->T,prob->Tf);
    465:   PetscFree3(prob->u,prob->u_t,prob->u_x);
    466:   PetscFree5(prob->x,prob->basisReal, prob->basisDerReal,prob->testReal,prob->testDerReal);
    467:   PetscFree6(prob->f0,prob->f1,prob->g0,prob->g1,prob->g2,prob->g3);
    468:   return(0);
    469: }

    471: static PetscErrorCode PetscDSEnlarge_Static(PetscDS prob, PetscInt NfNew)
    472: {
    473:   PetscObject      *tmpd;
    474:   PetscBool        *tmpi;
    475:   PetscInt         *tmpk;
    476:   PetscPointFunc   *tmpup;
    477:   PetscSimplePointFunc *tmpexactSol,  *tmpexactSol_t;
    478:   void                **tmpexactCtx, **tmpexactCtx_t;
    479:   void            **tmpctx;
    480:   PetscInt          Nf = prob->Nf, f;
    481:   PetscErrorCode    ierr;

    484:   if (Nf >= NfNew) return(0);
    485:   prob->setup = PETSC_FALSE;
    486:   PetscDSDestroyStructs_Static(prob);
    487:   PetscMalloc3(NfNew, &tmpd, NfNew, &tmpi, NfNew, &tmpk);
    488:   for (f = 0; f < Nf; ++f) {tmpd[f] = prob->disc[f]; tmpi[f] = prob->implicit[f]; tmpk[f] = prob->jetDegree[f];}
    489:   for (f = Nf; f < NfNew; ++f) {tmpd[f] = NULL; tmpi[f] = PETSC_TRUE; tmpk[f] = 1;}
    490:   PetscFree3(prob->disc, prob->implicit, prob->jetDegree);
    491:   PetscWeakFormSetNumFields(prob->wf, NfNew);
    492:   prob->Nf        = NfNew;
    493:   prob->disc      = tmpd;
    494:   prob->implicit  = tmpi;
    495:   prob->jetDegree = tmpk;
    496:   PetscCalloc2(NfNew, &tmpup, NfNew, &tmpctx);
    497:   for (f = 0; f < Nf; ++f) tmpup[f] = prob->update[f];
    498:   for (f = 0; f < Nf; ++f) tmpctx[f] = prob->ctx[f];
    499:   for (f = Nf; f < NfNew; ++f) tmpup[f] = NULL;
    500:   for (f = Nf; f < NfNew; ++f) tmpctx[f] = NULL;
    501:   PetscFree2(prob->update, prob->ctx);
    502:   prob->update = tmpup;
    503:   prob->ctx = tmpctx;
    504:   PetscCalloc4(NfNew, &tmpexactSol, NfNew, &tmpexactCtx, NfNew, &tmpexactSol_t, NfNew, &tmpexactCtx_t);
    505:   for (f = 0; f < Nf; ++f) tmpexactSol[f] = prob->exactSol[f];
    506:   for (f = 0; f < Nf; ++f) tmpexactCtx[f] = prob->exactCtx[f];
    507:   for (f = 0; f < Nf; ++f) tmpexactSol_t[f] = prob->exactSol_t[f];
    508:   for (f = 0; f < Nf; ++f) tmpexactCtx_t[f] = prob->exactCtx_t[f];
    509:   for (f = Nf; f < NfNew; ++f) tmpexactSol[f] = NULL;
    510:   for (f = Nf; f < NfNew; ++f) tmpexactCtx[f] = NULL;
    511:   for (f = Nf; f < NfNew; ++f) tmpexactSol_t[f] = NULL;
    512:   for (f = Nf; f < NfNew; ++f) tmpexactCtx_t[f] = NULL;
    513:   PetscFree4(prob->exactSol, prob->exactCtx, prob->exactSol_t, prob->exactCtx_t);
    514:   prob->exactSol = tmpexactSol;
    515:   prob->exactCtx = tmpexactCtx;
    516:   prob->exactSol_t = tmpexactSol_t;
    517:   prob->exactCtx_t = tmpexactCtx_t;
    518:   return(0);
    519: }

    521: /*@
    522:   PetscDSDestroy - Destroys a PetscDS object

    524:   Collective on prob

    526:   Input Parameter:
    527: . prob - the PetscDS object to destroy

    529:   Level: developer

    531: .seealso PetscDSView()
    532: @*/
    533: PetscErrorCode PetscDSDestroy(PetscDS *ds)
    534: {
    535:   PetscInt       f;

    539:   if (!*ds) return(0);

    542:   if (--((PetscObject)(*ds))->refct > 0) {*ds = NULL; return(0);}
    543:   ((PetscObject) (*ds))->refct = 0;
    544:   if ((*ds)->subprobs) {
    545:     PetscInt dim, d;

    547:     PetscDSGetSpatialDimension(*ds, &dim);
    548:     for (d = 0; d < dim; ++d) {PetscDSDestroy(&(*ds)->subprobs[d]);}
    549:   }
    550:   PetscFree((*ds)->subprobs);
    551:   PetscDSDestroyStructs_Static(*ds);
    552:   for (f = 0; f < (*ds)->Nf; ++f) {
    553:     PetscObjectDereference((*ds)->disc[f]);
    554:   }
    555:   PetscFree3((*ds)->disc, (*ds)->implicit, (*ds)->jetDegree);
    556:   PetscWeakFormDestroy(&(*ds)->wf);
    557:   PetscFree2((*ds)->update,(*ds)->ctx);
    558:   PetscFree4((*ds)->exactSol,(*ds)->exactCtx,(*ds)->exactSol_t,(*ds)->exactCtx_t);
    559:   if ((*ds)->ops->destroy) {(*(*ds)->ops->destroy)(*ds);}
    560:   PetscDSDestroyBoundary(*ds);
    561:   PetscFree((*ds)->constants);
    562:   PetscHeaderDestroy(ds);
    563:   return(0);
    564: }

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

    569:   Collective

    571:   Input Parameter:
    572: . comm - The communicator for the PetscDS object

    574:   Output Parameter:
    575: . ds   - The PetscDS object

    577:   Level: beginner

    579: .seealso: PetscDSSetType(), PETSCDSBASIC
    580: @*/
    581: PetscErrorCode PetscDSCreate(MPI_Comm comm, PetscDS *ds)
    582: {
    583:   PetscDS        p;

    588:   *ds  = NULL;
    589:   PetscDSInitializePackage();

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

    593:   p->Nf           = 0;
    594:   p->setup        = PETSC_FALSE;
    595:   p->numConstants = 0;
    596:   p->constants    = NULL;
    597:   p->dimEmbed     = -1;
    598:   p->useJacPre    = PETSC_TRUE;
    599:   PetscWeakFormCreate(comm, &p->wf);

    601:   *ds = p;
    602:   return(0);
    603: }

    605: /*@
    606:   PetscDSGetNumFields - Returns the number of fields in the DS

    608:   Not collective

    610:   Input Parameter:
    611: . prob - The PetscDS object

    613:   Output Parameter:
    614: . Nf - The number of fields

    616:   Level: beginner

    618: .seealso: PetscDSGetSpatialDimension(), PetscDSCreate()
    619: @*/
    620: PetscErrorCode PetscDSGetNumFields(PetscDS prob, PetscInt *Nf)
    621: {
    625:   *Nf = prob->Nf;
    626:   return(0);
    627: }

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

    632:   Not collective

    634:   Input Parameter:
    635: . prob - The PetscDS object

    637:   Output Parameter:
    638: . dim - The spatial dimension

    640:   Level: beginner

    642: .seealso: PetscDSGetCoordinateDimension(), PetscDSGetNumFields(), PetscDSCreate()
    643: @*/
    644: PetscErrorCode PetscDSGetSpatialDimension(PetscDS prob, PetscInt *dim)
    645: {

    651:   *dim = 0;
    652:   if (prob->Nf) {
    653:     PetscObject  obj;
    654:     PetscClassId id;

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

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

    670:   Not collective

    672:   Input Parameter:
    673: . prob - The PetscDS object

    675:   Output Parameter:
    676: . dimEmbed - The coordinate dimension

    678:   Level: beginner

    680: .seealso: PetscDSSetCoordinateDimension(), PetscDSGetSpatialDimension(), PetscDSGetNumFields(), PetscDSCreate()
    681: @*/
    682: PetscErrorCode PetscDSGetCoordinateDimension(PetscDS prob, PetscInt *dimEmbed)
    683: {
    687:   if (prob->dimEmbed < 0) SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONGSTATE, "No coordinate dimension set for this DS");
    688:   *dimEmbed = prob->dimEmbed;
    689:   return(0);
    690: }

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

    695:   Logically collective on prob

    697:   Input Parameters:
    698: + prob - The PetscDS object
    699: - dimEmbed - The coordinate dimension

    701:   Level: beginner

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

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

    717:   Not collective

    719:   Input Parameter:
    720: . prob - The PetscDS object

    722:   Output Parameter:
    723: . isHybrid - The flag

    725:   Level: developer

    727: .seealso: PetscDSSetHybrid(), PetscDSCreate()
    728: @*/
    729: PetscErrorCode PetscDSGetHybrid(PetscDS prob, PetscBool *isHybrid)
    730: {
    734:   *isHybrid = prob->isHybrid;
    735:   return(0);
    736: }

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

    741:   Not collective

    743:   Input Parameters:
    744: + prob - The PetscDS object
    745: - isHybrid - The flag

    747:   Level: developer

    749: .seealso: PetscDSGetHybrid(), PetscDSCreate()
    750: @*/
    751: PetscErrorCode PetscDSSetHybrid(PetscDS prob, PetscBool isHybrid)
    752: {
    755:   prob->isHybrid = isHybrid;
    756:   return(0);
    757: }

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

    762:   Not collective

    764:   Input Parameter:
    765: . prob - The PetscDS object

    767:   Output Parameter:
    768: . dim - The total problem dimension

    770:   Level: beginner

    772: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    773: @*/
    774: PetscErrorCode PetscDSGetTotalDimension(PetscDS prob, PetscInt *dim)
    775: {

    780:   PetscDSSetUp(prob);
    782:   *dim = prob->totDim;
    783:   return(0);
    784: }

    786: /*@
    787:   PetscDSGetTotalComponents - Returns the total number of components in this system

    789:   Not collective

    791:   Input Parameter:
    792: . prob - The PetscDS object

    794:   Output Parameter:
    795: . dim - The total number of components

    797:   Level: beginner

    799: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    800: @*/
    801: PetscErrorCode PetscDSGetTotalComponents(PetscDS prob, PetscInt *Nc)
    802: {

    807:   PetscDSSetUp(prob);
    809:   *Nc = prob->totComp;
    810:   return(0);
    811: }

    813: /*@
    814:   PetscDSGetDiscretization - Returns the discretization object for the given field

    816:   Not collective

    818:   Input Parameters:
    819: + prob - The PetscDS object
    820: - f - The field number

    822:   Output Parameter:
    823: . disc - The discretization object

    825:   Level: beginner

    827: .seealso: PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    828: @*/
    829: PetscErrorCode PetscDSGetDiscretization(PetscDS prob, PetscInt f, PetscObject *disc)
    830: {
    834:   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);
    835:   *disc = prob->disc[f];
    836:   return(0);
    837: }

    839: /*@
    840:   PetscDSSetDiscretization - Sets the discretization object for the given field

    842:   Not collective

    844:   Input Parameters:
    845: + prob - The PetscDS object
    846: . f - The field number
    847: - disc - The discretization object

    849:   Level: beginner

    851: .seealso: PetscDSGetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    852: @*/
    853: PetscErrorCode PetscDSSetDiscretization(PetscDS prob, PetscInt f, PetscObject disc)
    854: {

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

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

    879: /*@
    880:   PetscDSGetWeakForm - Returns the weak form object

    882:   Not collective

    884:   Input Parameter:
    885: . ds - The PetscDS object

    887:   Output Parameter:
    888: . wf - The weak form object

    890:   Level: beginner

    892: .seealso: PetscDSSetWeakForm(), PetscDSGetNumFields(), PetscDSCreate()
    893: @*/
    894: PetscErrorCode PetscDSGetWeakForm(PetscDS ds, PetscWeakForm *wf)
    895: {
    899:   *wf = ds->wf;
    900:   return(0);
    901: }

    903: /*@
    904:   PetscDSSetWeakForm - Sets the weak form object

    906:   Not collective

    908:   Input Parameters:
    909: + ds - The PetscDS object
    910: - wf - The weak form object

    912:   Level: beginner

    914: .seealso: PetscDSGetWeakForm(), PetscDSGetNumFields(), PetscDSCreate()
    915: @*/
    916: PetscErrorCode PetscDSSetWeakForm(PetscDS ds, PetscWeakForm wf)
    917: {

    923:   PetscObjectDereference((PetscObject) ds->wf);
    924:   ds->wf = wf;
    925:   PetscObjectReference((PetscObject) wf);
    926:   PetscWeakFormSetNumFields(wf, ds->Nf);
    927:   return(0);
    928: }

    930: /*@
    931:   PetscDSAddDiscretization - Adds a discretization object

    933:   Not collective

    935:   Input Parameters:
    936: + prob - The PetscDS object
    937: - disc - The boundary discretization object

    939:   Level: beginner

    941: .seealso: PetscDSGetDiscretization(), PetscDSSetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    942: @*/
    943: PetscErrorCode PetscDSAddDiscretization(PetscDS prob, PetscObject disc)
    944: {

    948:   PetscDSSetDiscretization(prob, prob->Nf, disc);
    949:   return(0);
    950: }

    952: /*@
    953:   PetscDSGetQuadrature - Returns the quadrature, which must agree for all fields in the DS

    955:   Not collective

    957:   Input Parameter:
    958: . prob - The PetscDS object

    960:   Output Parameter:
    961: . q - The quadrature object

    963: Level: intermediate

    965: .seealso: PetscDSSetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    966: @*/
    967: PetscErrorCode PetscDSGetQuadrature(PetscDS prob, PetscQuadrature *q)
    968: {
    969:   PetscObject    obj;
    970:   PetscClassId   id;

    974:   *q = NULL;
    975:   if (!prob->Nf) return(0);
    976:   PetscDSGetDiscretization(prob, 0, &obj);
    977:   PetscObjectGetClassId(obj, &id);
    978:   if      (id == PETSCFE_CLASSID) {PetscFEGetQuadrature((PetscFE) obj, q);}
    979:   else if (id == PETSCFV_CLASSID) {PetscFVGetQuadrature((PetscFV) obj, q);}
    980:   else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", 0);
    981:   return(0);
    982: }

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

    987:   Not collective

    989:   Input Parameters:
    990: + prob - The PetscDS object
    991: - f - The field number

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

    996:   Level: developer

    998: .seealso: PetscDSSetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    999: @*/
    1000: PetscErrorCode PetscDSGetImplicit(PetscDS prob, PetscInt f, PetscBool *implicit)
    1001: {
    1005:   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);
    1006:   *implicit = prob->implicit[f];
    1007:   return(0);
    1008: }

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

    1013:   Not collective

    1015:   Input Parameters:
    1016: + prob - The PetscDS object
    1017: . f - The field number
    1018: - implicit - The flag indicating what kind of solve to use for this field

    1020:   Level: developer

    1022: .seealso: PetscDSGetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    1023: @*/
    1024: PetscErrorCode PetscDSSetImplicit(PetscDS prob, PetscInt f, PetscBool implicit)
    1025: {
    1028:   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);
    1029:   prob->implicit[f] = implicit;
    1030:   return(0);
    1031: }

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

    1036:   Not collective

    1038:   Input Parameters:
    1039: + ds - The PetscDS object
    1040: - f  - The field number

    1042:   Output Parameter:
    1043: . k  - The highest derivative we need to tabulate

    1045:   Level: developer

    1047: .seealso: PetscDSSetJetDegree(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    1048: @*/
    1049: PetscErrorCode PetscDSGetJetDegree(PetscDS ds, PetscInt f, PetscInt *k)
    1050: {
    1054:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1055:   *k = ds->jetDegree[f];
    1056:   return(0);
    1057: }

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

    1062:   Not collective

    1064:   Input Parameters:
    1065: + ds - The PetscDS object
    1066: . f  - The field number
    1067: - k  - The highest derivative we need to tabulate

    1069:   Level: developer

    1071: .seealso: PetscDSGetJetDegree(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    1072: @*/
    1073: PetscErrorCode PetscDSSetJetDegree(PetscDS ds, PetscInt f, PetscInt k)
    1074: {
    1077:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1078:   ds->jetDegree[f] = k;
    1079:   return(0);
    1080: }

    1082: PetscErrorCode PetscDSGetObjective(PetscDS ds, PetscInt f,
    1083:                                    void (**obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1084:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1085:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1086:                                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
    1087: {
    1088:   PetscPointFunc *tmp;
    1089:   PetscInt        n;
    1090:   PetscErrorCode  ierr;

    1095:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1096:   PetscWeakFormGetObjective(ds->wf, NULL, 0, f, 0, &n, &tmp);
    1097:   *obj = tmp ? tmp[0] : NULL;
    1098:   return(0);
    1099: }

    1101: PetscErrorCode PetscDSSetObjective(PetscDS ds, PetscInt f,
    1102:                                    void (*obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1103:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1104:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1105:                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
    1106: {

    1112:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1113:   PetscWeakFormSetIndexObjective(ds->wf, NULL, 0, f, 0, 0, obj);
    1114:   return(0);
    1115: }

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

    1120:   Not collective

    1122:   Input Parameters:
    1123: + ds - The PetscDS
    1124: - f  - The test field number

    1126:   Output Parameters:
    1127: + f0 - integrand for the test function term
    1128: - f1 - integrand for the test function gradient term

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

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

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

    1136: $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1137: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1138: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1139: $    PetscReal t, const PetscReal x[], PetscScalar f0[])

    1141: + dim - the spatial dimension
    1142: . Nf - the number of fields
    1143: . uOff - the offset into u[] and u_t[] for each field
    1144: . uOff_x - the offset into u_x[] for each field
    1145: . u - each field evaluated at the current point
    1146: . u_t - the time derivative of each field evaluated at the current point
    1147: . u_x - the gradient of each field evaluated at the current point
    1148: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1149: . aOff_x - the offset into a_x[] for each auxiliary field
    1150: . a - each auxiliary field evaluated at the current point
    1151: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1152: . a_x - the gradient of auxiliary each field evaluated at the current point
    1153: . t - current time
    1154: . x - coordinates of the current point
    1155: . numConstants - number of constant parameters
    1156: . constants - constant parameters
    1157: - f0 - output values at the current point

    1159:   Level: intermediate

    1161: .seealso: PetscDSSetResidual()
    1162: @*/
    1163: PetscErrorCode PetscDSGetResidual(PetscDS ds, PetscInt f,
    1164:                                   void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1165:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1166:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1167:                                               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
    1168:                                   void (**f1)(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 x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
    1172: {
    1173:   PetscPointFunc *tmp0, *tmp1;
    1174:   PetscInt        n0, n1;
    1175:   PetscErrorCode  ierr;

    1179:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1180:   PetscWeakFormGetResidual(ds->wf, NULL, 0, f, 0, &n0, &tmp0, &n1, &tmp1);
    1181:   *f0  = tmp0 ? tmp0[0] : NULL;
    1182:   *f1  = tmp1 ? tmp1[0] : NULL;
    1183:   return(0);
    1184: }

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

    1189:   Not collective

    1191:   Input Parameters:
    1192: + ds - The PetscDS
    1193: . f  - The test field number
    1194: . f0 - integrand for the test function term
    1195: - f1 - integrand for the test function gradient term

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

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

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

    1203: $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1204: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1205: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1206: $    PetscReal t, const PetscReal x[], PetscScalar f0[])

    1208: + dim - the spatial dimension
    1209: . Nf - the number of fields
    1210: . uOff - the offset into u[] and u_t[] for each field
    1211: . uOff_x - the offset into u_x[] for each field
    1212: . u - each field evaluated at the current point
    1213: . u_t - the time derivative of each field evaluated at the current point
    1214: . u_x - the gradient of each field evaluated at the current point
    1215: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1216: . aOff_x - the offset into a_x[] for each auxiliary field
    1217: . a - each auxiliary field evaluated at the current point
    1218: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1219: . a_x - the gradient of auxiliary each field evaluated at the current point
    1220: . t - current time
    1221: . x - coordinates of the current point
    1222: . numConstants - number of constant parameters
    1223: . constants - constant parameters
    1224: - f0 - output values at the current point

    1226:   Level: intermediate

    1228: .seealso: PetscDSGetResidual()
    1229: @*/
    1230: PetscErrorCode PetscDSSetResidual(PetscDS ds, PetscInt f,
    1231:                                   void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1232:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1233:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1234:                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
    1235:                                   void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1236:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1237:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1238:                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
    1239: {

    1246:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1247:   PetscWeakFormSetIndexResidual(ds->wf, NULL, 0, f, 0, 0, f0, 0, f1);
    1248:   return(0);
    1249: }

    1251: /*@C
    1252:   PetscDSHasJacobian - Signals that Jacobian functions have been set

    1254:   Not collective

    1256:   Input Parameter:
    1257: . prob - The PetscDS

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

    1262:   Level: intermediate

    1264: .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
    1265: @*/
    1266: PetscErrorCode PetscDSHasJacobian(PetscDS ds, PetscBool *hasJac)
    1267: {

    1272:   PetscWeakFormHasJacobian(ds->wf, hasJac);
    1273:   return(0);
    1274: }

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

    1279:   Not collective

    1281:   Input Parameters:
    1282: + ds - The PetscDS
    1283: . f  - The test field number
    1284: - g  - The field number

    1286:   Output Parameters:
    1287: + g0 - integrand for the test and basis function term
    1288: . g1 - integrand for the test function and basis function gradient term
    1289: . g2 - integrand for the test function gradient and basis function term
    1290: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    1298: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1299: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1300: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1301: $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])

    1303: + dim - the spatial dimension
    1304: . Nf - the number of fields
    1305: . uOff - the offset into u[] and u_t[] for each field
    1306: . uOff_x - the offset into u_x[] for each field
    1307: . u - each field evaluated at the current point
    1308: . u_t - the time derivative of each field evaluated at the current point
    1309: . u_x - the gradient of each field evaluated at the current point
    1310: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1311: . aOff_x - the offset into a_x[] for each auxiliary field
    1312: . a - each auxiliary field evaluated at the current point
    1313: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1314: . a_x - the gradient of auxiliary each field evaluated at the current point
    1315: . t - current time
    1316: . u_tShift - the multiplier a for dF/dU_t
    1317: . x - coordinates of the current point
    1318: . numConstants - number of constant parameters
    1319: . constants - constant parameters
    1320: - g0 - output values at the current point

    1322:   Level: intermediate

    1324: .seealso: PetscDSSetJacobian()
    1325: @*/
    1326: PetscErrorCode PetscDSGetJacobian(PetscDS ds, PetscInt f, PetscInt g,
    1327:                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1328:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1329:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1330:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1331:                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1332:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1333:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1334:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1335:                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1336:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1337:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1338:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1339:                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1340:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1341:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1342:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1343: {
    1344:   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    1345:   PetscInt       n0, n1, n2, n3;

    1350:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1351:   if ((g < 0) || (g >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
    1352:   PetscWeakFormGetJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3);
    1353:   *g0  = tmp0 ? tmp0[0] : NULL;
    1354:   *g1  = tmp1 ? tmp1[0] : NULL;
    1355:   *g2  = tmp2 ? tmp2[0] : NULL;
    1356:   *g3  = tmp3 ? tmp3[0] : NULL;
    1357:   return(0);
    1358: }

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

    1363:   Not collective

    1365:   Input Parameters:
    1366: + ds - The PetscDS
    1367: . f  - The test field number
    1368: . g  - The field number
    1369: . g0 - integrand for the test and basis function term
    1370: . g1 - integrand for the test function and basis function gradient term
    1371: . g2 - integrand for the test function gradient and basis function term
    1372: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    1380: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1381: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1382: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1383: $    PetscReal t, const PetscReal x[], PetscScalar g0[])

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

    1404:   Level: intermediate

    1406: .seealso: PetscDSGetJacobian()
    1407: @*/
    1408: PetscErrorCode PetscDSSetJacobian(PetscDS ds, PetscInt f, PetscInt g,
    1409:                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1410:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1411:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1412:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1413:                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1414:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1415:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1416:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1417:                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1418:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1419:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1420:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1421:                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1422:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1423:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1424:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1425: {

    1434:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1435:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    1436:   PetscWeakFormSetIndexJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3);
    1437:   return(0);
    1438: }

    1440: /*@C
    1441:   PetscDSUseJacobianPreconditioner - Whether to construct a Jacobian preconditioner

    1443:   Not collective

    1445:   Input Parameters:
    1446: + prob - The PetscDS
    1447: - useJacPre - flag that enables construction of a Jacobian preconditioner

    1449:   Level: intermediate

    1451: .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
    1452: @*/
    1453: PetscErrorCode PetscDSUseJacobianPreconditioner(PetscDS prob, PetscBool useJacPre)
    1454: {
    1457:   prob->useJacPre = useJacPre;
    1458:   return(0);
    1459: }

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

    1464:   Not collective

    1466:   Input Parameter:
    1467: . prob - The PetscDS

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

    1472:   Level: intermediate

    1474: .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
    1475: @*/
    1476: PetscErrorCode PetscDSHasJacobianPreconditioner(PetscDS ds, PetscBool *hasJacPre)
    1477: {

    1482:   *hasJacPre = PETSC_FALSE;
    1483:   if (!ds->useJacPre) return(0);
    1484:   PetscWeakFormHasJacobianPreconditioner(ds->wf, hasJacPre);
    1485:   return(0);
    1486: }

    1488: /*@C
    1489:   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.

    1491:   Not collective

    1493:   Input Parameters:
    1494: + ds - The PetscDS
    1495: . f  - The test field number
    1496: - g  - The field number

    1498:   Output Parameters:
    1499: + g0 - integrand for the test and basis function term
    1500: . g1 - integrand for the test function and basis function gradient term
    1501: . g2 - integrand for the test function gradient and basis function term
    1502: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    1510: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1511: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1512: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1513: $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])

    1515: + dim - the spatial dimension
    1516: . Nf - the number of fields
    1517: . uOff - the offset into u[] and u_t[] for each field
    1518: . uOff_x - the offset into u_x[] for each field
    1519: . u - each field evaluated at the current point
    1520: . u_t - the time derivative of each field evaluated at the current point
    1521: . u_x - the gradient of each field evaluated at the current point
    1522: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1523: . aOff_x - the offset into a_x[] for each auxiliary field
    1524: . a - each auxiliary field evaluated at the current point
    1525: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1526: . a_x - the gradient of auxiliary each field evaluated at the current point
    1527: . t - current time
    1528: . u_tShift - the multiplier a for dF/dU_t
    1529: . x - coordinates of the current point
    1530: . numConstants - number of constant parameters
    1531: . constants - constant parameters
    1532: - g0 - output values at the current point

    1534:   Level: intermediate

    1536: .seealso: PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
    1537: @*/
    1538: PetscErrorCode PetscDSGetJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g,
    1539:                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1540:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1541:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1542:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1543:                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1544:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1545:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1546:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1547:                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1548:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1549:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1550:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1551:                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1552:                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1553:                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1554:                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1555: {
    1556:   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    1557:   PetscInt       n0, n1, n2, n3;

    1562:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1563:   if ((g < 0) || (g >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
    1564:   PetscWeakFormGetJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3);
    1565:   *g0  = tmp0 ? tmp0[0] : NULL;
    1566:   *g1  = tmp1 ? tmp1[0] : NULL;
    1567:   *g2  = tmp2 ? tmp2[0] : NULL;
    1568:   *g3  = tmp3 ? tmp3[0] : NULL;
    1569:   return(0);
    1570: }

    1572: /*@C
    1573:   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.

    1575:   Not collective

    1577:   Input Parameters:
    1578: + ds - The PetscDS
    1579: . f  - The test field number
    1580: . g  - The field number
    1581: . g0 - integrand for the test and basis function term
    1582: . g1 - integrand for the test function and basis function gradient term
    1583: . g2 - integrand for the test function gradient and basis function term
    1584: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    1592: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1593: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1594: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1595: $    PetscReal t, const PetscReal x[], PetscScalar g0[])

    1597: + dim - the spatial dimension
    1598: . Nf - the number of fields
    1599: . uOff - the offset into u[] and u_t[] for each field
    1600: . uOff_x - the offset into u_x[] for each field
    1601: . u - each field evaluated at the current point
    1602: . u_t - the time derivative of each field evaluated at the current point
    1603: . u_x - the gradient of each field evaluated at the current point
    1604: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1605: . aOff_x - the offset into a_x[] for each auxiliary field
    1606: . a - each auxiliary field evaluated at the current point
    1607: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1608: . a_x - the gradient of auxiliary each field evaluated at the current point
    1609: . t - current time
    1610: . u_tShift - the multiplier a for dF/dU_t
    1611: . x - coordinates of the current point
    1612: . numConstants - number of constant parameters
    1613: . constants - constant parameters
    1614: - g0 - output values at the current point

    1616:   Level: intermediate

    1618: .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobian()
    1619: @*/
    1620: PetscErrorCode PetscDSSetJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g,
    1621:                                   void (*g0)(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 g0[]),
    1625:                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1626:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1627:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1628:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1629:                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1630:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1631:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1632:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1633:                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1634:                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1635:                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1636:                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1637: {

    1646:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1647:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    1648:   PetscWeakFormSetIndexJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3);
    1649:   return(0);
    1650: }

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

    1655:   Not collective

    1657:   Input Parameter:
    1658: . ds - The PetscDS

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

    1663:   Level: intermediate

    1665: .seealso: PetscDSGetDynamicJacobian(), PetscDSSetDynamicJacobian(), PetscDSGetJacobian()
    1666: @*/
    1667: PetscErrorCode PetscDSHasDynamicJacobian(PetscDS ds, PetscBool *hasDynJac)
    1668: {

    1673:   PetscWeakFormHasDynamicJacobian(ds->wf, hasDynJac);
    1674:   return(0);
    1675: }

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

    1680:   Not collective

    1682:   Input Parameters:
    1683: + ds - The PetscDS
    1684: . f  - The test field number
    1685: - g  - The field number

    1687:   Output Parameters:
    1688: + g0 - integrand for the test and basis function term
    1689: . g1 - integrand for the test function and basis function gradient term
    1690: . g2 - integrand for the test function gradient and basis function term
    1691: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    1699: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1700: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1701: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1702: $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])

    1704: + dim - the spatial dimension
    1705: . Nf - the number of fields
    1706: . uOff - the offset into u[] and u_t[] for each field
    1707: . uOff_x - the offset into u_x[] for each field
    1708: . u - each field evaluated at the current point
    1709: . u_t - the time derivative of each field evaluated at the current point
    1710: . u_x - the gradient of each field evaluated at the current point
    1711: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1712: . aOff_x - the offset into a_x[] for each auxiliary field
    1713: . a - each auxiliary field evaluated at the current point
    1714: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1715: . a_x - the gradient of auxiliary each field evaluated at the current point
    1716: . t - current time
    1717: . u_tShift - the multiplier a for dF/dU_t
    1718: . x - coordinates of the current point
    1719: . numConstants - number of constant parameters
    1720: . constants - constant parameters
    1721: - g0 - output values at the current point

    1723:   Level: intermediate

    1725: .seealso: PetscDSSetJacobian()
    1726: @*/
    1727: PetscErrorCode PetscDSGetDynamicJacobian(PetscDS ds, PetscInt f, PetscInt g,
    1728:                                          void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1729:                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1730:                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1731:                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1732:                                          void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1733:                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1734:                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1735:                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1736:                                          void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1737:                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1738:                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1739:                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1740:                                          void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1741:                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1742:                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1743:                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1744: {
    1745:   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    1746:   PetscInt       n0, n1, n2, n3;

    1751:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1752:   if ((g < 0) || (g >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
    1753:   PetscWeakFormGetDynamicJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3);
    1754:   *g0  = tmp0 ? tmp0[0] : NULL;
    1755:   *g1  = tmp1 ? tmp1[0] : NULL;
    1756:   *g2  = tmp2 ? tmp2[0] : NULL;
    1757:   *g3  = tmp3 ? tmp3[0] : NULL;
    1758:   return(0);
    1759: }

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

    1764:   Not collective

    1766:   Input Parameters:
    1767: + ds - The PetscDS
    1768: . f  - The test field number
    1769: . g  - The field number
    1770: . g0 - integrand for the test and basis function term
    1771: . g1 - integrand for the test function and basis function gradient term
    1772: . g2 - integrand for the test function gradient and basis function term
    1773: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    1781: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1782: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1783: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1784: $    PetscReal t, const PetscReal x[], PetscScalar g0[])

    1786: + dim - the spatial dimension
    1787: . Nf - the number of fields
    1788: . uOff - the offset into u[] and u_t[] for each field
    1789: . uOff_x - the offset into u_x[] for each field
    1790: . u - each field evaluated at the current point
    1791: . u_t - the time derivative of each field evaluated at the current point
    1792: . u_x - the gradient of each field evaluated at the current point
    1793: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1794: . aOff_x - the offset into a_x[] for each auxiliary field
    1795: . a - each auxiliary field evaluated at the current point
    1796: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1797: . a_x - the gradient of auxiliary each field evaluated at the current point
    1798: . t - current time
    1799: . u_tShift - the multiplier a for dF/dU_t
    1800: . x - coordinates of the current point
    1801: . numConstants - number of constant parameters
    1802: . constants - constant parameters
    1803: - g0 - output values at the current point

    1805:   Level: intermediate

    1807: .seealso: PetscDSGetJacobian()
    1808: @*/
    1809: PetscErrorCode PetscDSSetDynamicJacobian(PetscDS ds, PetscInt f, PetscInt g,
    1810:                                          void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1811:                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1812:                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1813:                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    1814:                                          void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1815:                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1816:                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1817:                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    1818:                                          void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1819:                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1820:                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1821:                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    1822:                                          void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1823:                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1824:                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1825:                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    1826: {

    1835:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1836:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    1837:   PetscWeakFormSetIndexDynamicJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3);
    1838:   return(0);
    1839: }

    1841: /*@C
    1842:   PetscDSGetRiemannSolver - Returns the Riemann solver for the given field

    1844:   Not collective

    1846:   Input Parameters:
    1847: + ds - The PetscDS object
    1848: - f  - The field number

    1850:   Output Parameter:
    1851: . r    - Riemann solver

    1853:   Calling sequence for r:

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

    1857: + dim  - The spatial dimension
    1858: . Nf   - The number of fields
    1859: . x    - The coordinates at a point on the interface
    1860: . n    - The normal vector to the interface
    1861: . uL   - The state vector to the left of the interface
    1862: . uR   - The state vector to the right of the interface
    1863: . flux - output array of flux through the interface
    1864: . numConstants - number of constant parameters
    1865: . constants - constant parameters
    1866: - ctx  - optional user context

    1868:   Level: intermediate

    1870: .seealso: PetscDSSetRiemannSolver()
    1871: @*/
    1872: PetscErrorCode PetscDSGetRiemannSolver(PetscDS ds, PetscInt f,
    1873:                                        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))
    1874: {
    1875:   PetscRiemannFunc *tmp;
    1876:   PetscInt          n;
    1877:   PetscErrorCode    ierr;

    1882:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1883:   PetscWeakFormGetRiemannSolver(ds->wf, NULL, 0, f, 0, &n, &tmp);
    1884:   *r   = tmp ? tmp[0] : NULL;
    1885:   return(0);
    1886: }

    1888: /*@C
    1889:   PetscDSSetRiemannSolver - Sets the Riemann solver for the given field

    1891:   Not collective

    1893:   Input Parameters:
    1894: + ds - The PetscDS object
    1895: . f  - The field number
    1896: - r  - Riemann solver

    1898:   Calling sequence for r:

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

    1902: + dim  - The spatial dimension
    1903: . Nf   - The number of fields
    1904: . x    - The coordinates at a point on the interface
    1905: . n    - The normal vector to the interface
    1906: . uL   - The state vector to the left of the interface
    1907: . uR   - The state vector to the right of the interface
    1908: . flux - output array of flux through the interface
    1909: . numConstants - number of constant parameters
    1910: . constants - constant parameters
    1911: - ctx  - optional user context

    1913:   Level: intermediate

    1915: .seealso: PetscDSGetRiemannSolver()
    1916: @*/
    1917: PetscErrorCode PetscDSSetRiemannSolver(PetscDS ds, PetscInt f,
    1918:                                        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))
    1919: {

    1925:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    1926:   PetscWeakFormSetIndexRiemannSolver(ds->wf, NULL, 0, f, 0, 0, r);
    1927:   return(0);
    1928: }

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

    1933:   Not collective

    1935:   Input Parameters:
    1936: + ds - The PetscDS
    1937: - f  - The field number

    1939:   Output Parameter:
    1940: . update - update function

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

    1944: $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1945: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1946: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1947: $        PetscReal t, const PetscReal x[], PetscScalar uNew[])

    1949: + dim - the spatial dimension
    1950: . Nf - the number of fields
    1951: . uOff - the offset into u[] and u_t[] for each field
    1952: . uOff_x - the offset into u_x[] for each field
    1953: . u - each field evaluated at the current point
    1954: . u_t - the time derivative of each field evaluated at the current point
    1955: . u_x - the gradient of each field evaluated at the current point
    1956: . aOff - the offset into a[] and a_t[] for each auxiliary field
    1957: . aOff_x - the offset into a_x[] for each auxiliary field
    1958: . a - each auxiliary field evaluated at the current point
    1959: . a_t - the time derivative of each auxiliary field evaluated at the current point
    1960: . a_x - the gradient of auxiliary each field evaluated at the current point
    1961: . t - current time
    1962: . x - coordinates of the current point
    1963: - uNew - new value for field at the current point

    1965:   Level: intermediate

    1967: .seealso: PetscDSSetUpdate(), PetscDSSetResidual()
    1968: @*/
    1969: PetscErrorCode PetscDSGetUpdate(PetscDS ds, PetscInt f,
    1970:                                   void (**update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1971:                                                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1972:                                                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1973:                                                   PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
    1974: {
    1977:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    1979:   return(0);
    1980: }

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

    1985:   Not collective

    1987:   Input Parameters:
    1988: + ds     - The PetscDS
    1989: . f      - The field number
    1990: - update - update function

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

    1994: $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    1995: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    1996: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    1997: $        PetscReal t, const PetscReal x[], PetscScalar uNew[])

    1999: + dim - the spatial dimension
    2000: . Nf - the number of fields
    2001: . uOff - the offset into u[] and u_t[] for each field
    2002: . uOff_x - the offset into u_x[] for each field
    2003: . u - each field evaluated at the current point
    2004: . u_t - the time derivative of each field evaluated at the current point
    2005: . u_x - the gradient of each field evaluated at the current point
    2006: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2007: . aOff_x - the offset into a_x[] for each auxiliary field
    2008: . a - each auxiliary field evaluated at the current point
    2009: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2010: . a_x - the gradient of auxiliary each field evaluated at the current point
    2011: . t - current time
    2012: . x - coordinates of the current point
    2013: - uNew - new field values at the current point

    2015:   Level: intermediate

    2017: .seealso: PetscDSGetResidual()
    2018: @*/
    2019: PetscErrorCode PetscDSSetUpdate(PetscDS ds, PetscInt f,
    2020:                                 void (*update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2021:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2022:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2023:                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
    2024: {

    2030:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2031:   PetscDSEnlarge_Static(ds, f+1);
    2032:   ds->update[f] = update;
    2033:   return(0);
    2034: }

    2036: PetscErrorCode PetscDSGetContext(PetscDS ds, PetscInt f, void *ctx)
    2037: {
    2040:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    2042:   *(void**)ctx = ds->ctx[f];
    2043:   return(0);
    2044: }

    2046: PetscErrorCode PetscDSSetContext(PetscDS ds, PetscInt f, void *ctx)
    2047: {

    2052:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2053:   PetscDSEnlarge_Static(ds, f+1);
    2054:   ds->ctx[f] = ctx;
    2055:   return(0);
    2056: }

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

    2061:   Not collective

    2063:   Input Parameters:
    2064: + ds - The PetscDS
    2065: - f  - The test field number

    2067:   Output Parameters:
    2068: + f0 - boundary integrand for the test function term
    2069: - f1 - boundary integrand for the test function gradient term

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

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

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

    2077: $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2078: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2079: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2080: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])

    2082: + dim - the spatial dimension
    2083: . Nf - the number of fields
    2084: . uOff - the offset into u[] and u_t[] for each field
    2085: . uOff_x - the offset into u_x[] for each field
    2086: . u - each field evaluated at the current point
    2087: . u_t - the time derivative of each field evaluated at the current point
    2088: . u_x - the gradient of each field evaluated at the current point
    2089: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2090: . aOff_x - the offset into a_x[] for each auxiliary field
    2091: . a - each auxiliary field evaluated at the current point
    2092: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2093: . a_x - the gradient of auxiliary each field evaluated at the current point
    2094: . t - current time
    2095: . x - coordinates of the current point
    2096: . n - unit normal at the current point
    2097: . numConstants - number of constant parameters
    2098: . constants - constant parameters
    2099: - f0 - output values at the current point

    2101:   Level: intermediate

    2103: .seealso: PetscDSSetBdResidual()
    2104: @*/
    2105: PetscErrorCode PetscDSGetBdResidual(PetscDS ds, PetscInt f,
    2106:                                     void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2107:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2108:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2109:                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
    2110:                                     void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2111:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2112:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2113:                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
    2114: {
    2115:   PetscBdPointFunc *tmp0, *tmp1;
    2116:   PetscInt          n0, n1;
    2117:   PetscErrorCode    ierr;

    2121:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    2122:   PetscWeakFormGetBdResidual(ds->wf, NULL, 0, f, 0, &n0, &tmp0, &n1, &tmp1);
    2123:   *f0  = tmp0 ? tmp0[0] : NULL;
    2124:   *f1  = tmp1 ? tmp1[0] : NULL;
    2125:   return(0);
    2126: }

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

    2131:   Not collective

    2133:   Input Parameters:
    2134: + ds - The PetscDS
    2135: . f  - The test field number
    2136: . f0 - boundary integrand for the test function term
    2137: - f1 - boundary integrand for the test function gradient term

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

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

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

    2145: $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2146: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2147: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2148: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])

    2150: + dim - the spatial dimension
    2151: . Nf - the number of fields
    2152: . uOff - the offset into u[] and u_t[] for each field
    2153: . uOff_x - the offset into u_x[] for each field
    2154: . u - each field evaluated at the current point
    2155: . u_t - the time derivative of each field evaluated at the current point
    2156: . u_x - the gradient of each field evaluated at the current point
    2157: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2158: . aOff_x - the offset into a_x[] for each auxiliary field
    2159: . a - each auxiliary field evaluated at the current point
    2160: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2161: . a_x - the gradient of auxiliary each field evaluated at the current point
    2162: . t - current time
    2163: . x - coordinates of the current point
    2164: . n - unit normal at the current point
    2165: . numConstants - number of constant parameters
    2166: . constants - constant parameters
    2167: - f0 - output values at the current point

    2169:   Level: intermediate

    2171: .seealso: PetscDSGetBdResidual()
    2172: @*/
    2173: PetscErrorCode PetscDSSetBdResidual(PetscDS ds, PetscInt f,
    2174:                                     void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2175:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2176:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2177:                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
    2178:                                     void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2179:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2180:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2181:                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
    2182: {

    2187:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2188:   PetscWeakFormSetIndexBdResidual(ds->wf, NULL, 0, f, 0, 0, f0, 0, f1);
    2189:   return(0);
    2190: }

    2192: /*@
    2193:   PetscDSHasBdJacobian - Signals that boundary Jacobian functions have been set

    2195:   Not collective

    2197:   Input Parameter:
    2198: . ds - The PetscDS

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

    2203:   Level: intermediate

    2205: .seealso: PetscDSHasJacobian(), PetscDSSetBdJacobian(), PetscDSGetBdJacobian()
    2206: @*/
    2207: PetscErrorCode PetscDSHasBdJacobian(PetscDS ds, PetscBool *hasBdJac)
    2208: {

    2214:   PetscWeakFormHasBdJacobian(ds->wf, hasBdJac);
    2215:   return(0);
    2216: }

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

    2221:   Not collective

    2223:   Input Parameters:
    2224: + ds - The PetscDS
    2225: . f  - The test field number
    2226: - g  - The field number

    2228:   Output Parameters:
    2229: + g0 - integrand for the test and basis function term
    2230: . g1 - integrand for the test function and basis function gradient term
    2231: . g2 - integrand for the test function gradient and basis function term
    2232: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    2240: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2241: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2242: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2243: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])

    2245: + dim - the spatial dimension
    2246: . Nf - the number of fields
    2247: . uOff - the offset into u[] and u_t[] for each field
    2248: . uOff_x - the offset into u_x[] for each field
    2249: . u - each field evaluated at the current point
    2250: . u_t - the time derivative of each field evaluated at the current point
    2251: . u_x - the gradient of each field evaluated at the current point
    2252: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2253: . aOff_x - the offset into a_x[] for each auxiliary field
    2254: . a - each auxiliary field evaluated at the current point
    2255: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2256: . a_x - the gradient of auxiliary each field evaluated at the current point
    2257: . t - current time
    2258: . u_tShift - the multiplier a for dF/dU_t
    2259: . x - coordinates of the current point
    2260: . n - normal at the current point
    2261: . numConstants - number of constant parameters
    2262: . constants - constant parameters
    2263: - g0 - output values at the current point

    2265:   Level: intermediate

    2267: .seealso: PetscDSSetBdJacobian()
    2268: @*/
    2269: PetscErrorCode PetscDSGetBdJacobian(PetscDS ds, PetscInt f, PetscInt g,
    2270:                                     void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2271:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2272:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2273:                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    2274:                                     void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2275:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2276:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2277:                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    2278:                                     void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2279:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2280:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2281:                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    2282:                                     void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2283:                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2284:                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2285:                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    2286: {
    2287:   PetscBdPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    2288:   PetscInt         n0, n1, n2, n3;
    2289:   PetscErrorCode   ierr;

    2293:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    2294:   if ((g < 0) || (g >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
    2295:   PetscWeakFormGetBdJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3);
    2296:   *g0  = tmp0 ? tmp0[0] : NULL;
    2297:   *g1  = tmp1 ? tmp1[0] : NULL;
    2298:   *g2  = tmp2 ? tmp2[0] : NULL;
    2299:   *g3  = tmp3 ? tmp3[0] : NULL;
    2300:   return(0);
    2301: }

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

    2306:   Not collective

    2308:   Input Parameters:
    2309: + ds - The PetscDS
    2310: . f  - The test field number
    2311: . g  - The field number
    2312: . g0 - integrand for the test and basis function term
    2313: . g1 - integrand for the test function and basis function gradient term
    2314: . g2 - integrand for the test function gradient and basis function term
    2315: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    2323: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2324: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2325: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2326: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])

    2328: + dim - the spatial dimension
    2329: . Nf - the number of fields
    2330: . uOff - the offset into u[] and u_t[] for each field
    2331: . uOff_x - the offset into u_x[] for each field
    2332: . u - each field evaluated at the current point
    2333: . u_t - the time derivative of each field evaluated at the current point
    2334: . u_x - the gradient of each field evaluated at the current point
    2335: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2336: . aOff_x - the offset into a_x[] for each auxiliary field
    2337: . a - each auxiliary field evaluated at the current point
    2338: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2339: . a_x - the gradient of auxiliary each field evaluated at the current point
    2340: . t - current time
    2341: . u_tShift - the multiplier a for dF/dU_t
    2342: . x - coordinates of the current point
    2343: . n - normal at the current point
    2344: . numConstants - number of constant parameters
    2345: . constants - constant parameters
    2346: - g0 - output values at the current point

    2348:   Level: intermediate

    2350: .seealso: PetscDSGetBdJacobian()
    2351: @*/
    2352: PetscErrorCode PetscDSSetBdJacobian(PetscDS ds, PetscInt f, PetscInt g,
    2353:                                     void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2354:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2355:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2356:                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    2357:                                     void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2358:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2359:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2360:                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    2361:                                     void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2362:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2363:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2364:                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    2365:                                     void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2366:                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2367:                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2368:                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    2369: {

    2378:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2379:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    2380:   PetscWeakFormSetIndexBdJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3);
    2381:   return(0);
    2382: }

    2384: /*@
    2385:   PetscDSHasBdJacobianPreconditioner - Signals that boundary Jacobian preconditioner functions have been set

    2387:   Not collective

    2389:   Input Parameter:
    2390: . ds - The PetscDS

    2392:   Output Parameter:
    2393: . hasBdJac - flag that pointwise function for the boundary Jacobian preconditioner has been set

    2395:   Level: intermediate

    2397: .seealso: PetscDSHasJacobian(), PetscDSSetBdJacobian(), PetscDSGetBdJacobian()
    2398: @*/
    2399: PetscErrorCode PetscDSHasBdJacobianPreconditioner(PetscDS ds, PetscBool *hasBdJacPre)
    2400: {

    2406:   PetscWeakFormHasBdJacobianPreconditioner(ds->wf, hasBdJacPre);
    2407:   return(0);
    2408: }

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

    2413:   Not collective

    2415:   Input Parameters:
    2416: + ds - The PetscDS
    2417: . f  - The test field number
    2418: - g  - The field number

    2420:   Output Parameters:
    2421: + g0 - integrand for the test and basis function term
    2422: . g1 - integrand for the test function and basis function gradient term
    2423: . g2 - integrand for the test function gradient and basis function term
    2424: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    2432: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2433: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2434: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2435: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])

    2437: + dim - the spatial dimension
    2438: . Nf - the number of fields
    2439: . NfAux - the number of auxiliary fields
    2440: . uOff - the offset into u[] and u_t[] for each field
    2441: . uOff_x - the offset into u_x[] for each field
    2442: . u - each field evaluated at the current point
    2443: . u_t - the time derivative of each field evaluated at the current point
    2444: . u_x - the gradient of each field evaluated at the current point
    2445: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2446: . aOff_x - the offset into a_x[] for each auxiliary field
    2447: . a - each auxiliary field evaluated at the current point
    2448: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2449: . a_x - the gradient of auxiliary each field evaluated at the current point
    2450: . t - current time
    2451: . u_tShift - the multiplier a for dF/dU_t
    2452: . x - coordinates of the current point
    2453: . n - normal at the current point
    2454: . numConstants - number of constant parameters
    2455: . constants - constant parameters
    2456: - g0 - output values at the current point

    2458:   This is not yet available in Fortran.

    2460:   Level: intermediate

    2462: .seealso: PetscDSSetBdJacobianPreconditioner()
    2463: @*/
    2464: PetscErrorCode PetscDSGetBdJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g,
    2465:                                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2466:                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2467:                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2468:                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    2469:                                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2470:                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2471:                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2472:                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    2473:                                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2474:                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2475:                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2476:                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    2477:                                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2478:                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2479:                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2480:                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    2481: {
    2482:   PetscBdPointJac *tmp0, *tmp1, *tmp2, *tmp3;
    2483:   PetscInt         n0, n1, n2, n3;
    2484:   PetscErrorCode   ierr;

    2488:   if ((f < 0) || (f >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
    2489:   if ((g < 0) || (g >= ds->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
    2490:   PetscWeakFormGetBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3);
    2491:   *g0  = tmp0 ? tmp0[0] : NULL;
    2492:   *g1  = tmp1 ? tmp1[0] : NULL;
    2493:   *g2  = tmp2 ? tmp2[0] : NULL;
    2494:   *g3  = tmp3 ? tmp3[0] : NULL;
    2495:   return(0);
    2496: }

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

    2501:   Not collective

    2503:   Input Parameters:
    2504: + ds - The PetscDS
    2505: . f  - The test field number
    2506: . g  - The field number
    2507: . g0 - integrand for the test and basis function term
    2508: . g1 - integrand for the test function and basis function gradient term
    2509: . g2 - integrand for the test function gradient and basis function term
    2510: - g3 - integrand for the test function gradient and basis function gradient term

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

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

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

    2518: $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2519: $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2520: $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2521: $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])

    2523: + dim - the spatial dimension
    2524: . Nf - the number of fields
    2525: . NfAux - the number of auxiliary fields
    2526: . uOff - the offset into u[] and u_t[] for each field
    2527: . uOff_x - the offset into u_x[] for each field
    2528: . u - each field evaluated at the current point
    2529: . u_t - the time derivative of each field evaluated at the current point
    2530: . u_x - the gradient of each field evaluated at the current point
    2531: . aOff - the offset into a[] and a_t[] for each auxiliary field
    2532: . aOff_x - the offset into a_x[] for each auxiliary field
    2533: . a - each auxiliary field evaluated at the current point
    2534: . a_t - the time derivative of each auxiliary field evaluated at the current point
    2535: . a_x - the gradient of auxiliary each field evaluated at the current point
    2536: . t - current time
    2537: . u_tShift - the multiplier a for dF/dU_t
    2538: . x - coordinates of the current point
    2539: . n - normal at the current point
    2540: . numConstants - number of constant parameters
    2541: . constants - constant parameters
    2542: - g0 - output values at the current point

    2544:   This is not yet available in Fortran.

    2546:   Level: intermediate

    2548: .seealso: PetscDSGetBdJacobianPreconditioner()
    2549: @*/
    2550: PetscErrorCode PetscDSSetBdJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g,
    2551:                                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2552:                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2553:                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2554:                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
    2555:                                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2556:                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2557:                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2558:                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
    2559:                                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2560:                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2561:                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2562:                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
    2563:                                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    2564:                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    2565:                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    2566:                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
    2567: {

    2576:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2577:   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
    2578:   PetscWeakFormSetIndexBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3);
    2579:   return(0);
    2580: }

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

    2585:   Not collective

    2587:   Input Parameters:
    2588: + prob - The PetscDS
    2589: - f    - The test field number

    2591:   Output Parameters:
    2592: + exactSol - exact solution for the test field
    2593: - exactCtx - exact solution context

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

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

    2599: + dim - the spatial dimension
    2600: . t - current time
    2601: . x - coordinates of the current point
    2602: . Nc - the number of field components
    2603: . u - the solution field evaluated at the current point
    2604: - ctx - a user context

    2606:   Level: intermediate

    2608: .seealso: PetscDSSetExactSolution(), PetscDSGetExactSolutionTimeDerivative()
    2609: @*/
    2610: PetscErrorCode PetscDSGetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
    2611: {
    2614:   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);
    2617:   return(0);
    2618: }

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

    2623:   Not collective

    2625:   Input Parameters:
    2626: + prob - The PetscDS
    2627: . f    - The test field number
    2628: . sol  - solution function for the test fields
    2629: - ctx  - solution context or NULL

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

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

    2635: + dim - the spatial dimension
    2636: . t - current time
    2637: . x - coordinates of the current point
    2638: . Nc - the number of field components
    2639: . u - the solution field evaluated at the current point
    2640: - ctx - a user context

    2642:   Level: intermediate

    2644: .seealso: PetscDSGetExactSolution()
    2645: @*/
    2646: PetscErrorCode PetscDSSetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
    2647: {

    2652:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2653:   PetscDSEnlarge_Static(prob, f+1);
    2656:   return(0);
    2657: }

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

    2662:   Not collective

    2664:   Input Parameters:
    2665: + prob - The PetscDS
    2666: - f    - The test field number

    2668:   Output Parameters:
    2669: + exactSol - time derivative of the exact solution for the test field
    2670: - exactCtx - time derivative of the exact solution context

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

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

    2676: + dim - the spatial dimension
    2677: . t - current time
    2678: . x - coordinates of the current point
    2679: . Nc - the number of field components
    2680: . u - the solution field evaluated at the current point
    2681: - ctx - a user context

    2683:   Level: intermediate

    2685: .seealso: PetscDSSetExactSolutionTimeDerivative(), PetscDSGetExactSolution()
    2686: @*/
    2687: PetscErrorCode PetscDSGetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
    2688: {
    2691:   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);
    2694:   return(0);
    2695: }

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

    2700:   Not collective

    2702:   Input Parameters:
    2703: + prob - The PetscDS
    2704: . f    - The test field number
    2705: . sol  - time derivative of the solution function for the test fields
    2706: - ctx  - time derivative of the solution context or NULL

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

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

    2712: + dim - the spatial dimension
    2713: . t - current time
    2714: . x - coordinates of the current point
    2715: . Nc - the number of field components
    2716: . u - the solution field evaluated at the current point
    2717: - ctx - a user context

    2719:   Level: intermediate

    2721: .seealso: PetscDSGetExactSolutionTimeDerivative(), PetscDSSetExactSolution()
    2722: @*/
    2723: PetscErrorCode PetscDSSetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
    2724: {

    2729:   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
    2730:   PetscDSEnlarge_Static(prob, f+1);
    2733:   return(0);
    2734: }

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

    2739:   Not collective

    2741:   Input Parameter:
    2742: . prob - The PetscDS object

    2744:   Output Parameters:
    2745: + numConstants - The number of constants
    2746: - constants    - The array of constants, NULL if there are none

    2748:   Level: intermediate

    2750: .seealso: PetscDSSetConstants(), PetscDSCreate()
    2751: @*/
    2752: PetscErrorCode PetscDSGetConstants(PetscDS prob, PetscInt *numConstants, const PetscScalar *constants[])
    2753: {
    2758:   return(0);
    2759: }

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

    2764:   Not collective

    2766:   Input Parameters:
    2767: + prob         - The PetscDS object
    2768: . numConstants - The number of constants
    2769: - constants    - The array of constants, NULL if there are none

    2771:   Level: intermediate

    2773: .seealso: PetscDSGetConstants(), PetscDSCreate()
    2774: @*/
    2775: PetscErrorCode PetscDSSetConstants(PetscDS prob, PetscInt numConstants, PetscScalar constants[])
    2776: {

    2781:   if (numConstants != prob->numConstants) {
    2782:     PetscFree(prob->constants);
    2783:     prob->numConstants = numConstants;
    2784:     if (prob->numConstants) {
    2785:       PetscMalloc1(prob->numConstants, &prob->constants);
    2786:     } else {
    2787:       prob->constants = NULL;
    2788:     }
    2789:   }
    2790:   if (prob->numConstants) {
    2792:     PetscArraycpy(prob->constants, constants, prob->numConstants);
    2793:   }
    2794:   return(0);
    2795: }

    2797: /*@
    2798:   PetscDSGetFieldIndex - Returns the index of the given field

    2800:   Not collective

    2802:   Input Parameters:
    2803: + prob - The PetscDS object
    2804: - disc - The discretization object

    2806:   Output Parameter:
    2807: . f - The field number

    2809:   Level: beginner

    2811: .seealso: PetscGetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
    2812: @*/
    2813: PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
    2814: {
    2815:   PetscInt g;

    2820:   *f = -1;
    2821:   for (g = 0; g < prob->Nf; ++g) {if (disc == prob->disc[g]) break;}
    2822:   if (g == prob->Nf) SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
    2823:   *f = g;
    2824:   return(0);
    2825: }

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

    2830:   Not collective

    2832:   Input Parameters:
    2833: + prob - The PetscDS object
    2834: - f - The field number

    2836:   Output Parameter:
    2837: . size - The size

    2839:   Level: beginner

    2841: .seealso: PetscDSGetFieldOffset(), PetscDSGetNumFields(), PetscDSCreate()
    2842: @*/
    2843: PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
    2844: {

    2850:   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);
    2851:   PetscDSSetUp(prob);
    2852:   *size = prob->Nb[f];
    2853:   return(0);
    2854: }

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

    2859:   Not collective

    2861:   Input Parameters:
    2862: + prob - The PetscDS object
    2863: - f - The field number

    2865:   Output Parameter:
    2866: . off - The offset

    2868:   Level: beginner

    2870: .seealso: PetscDSGetFieldSize(), PetscDSGetNumFields(), PetscDSCreate()
    2871: @*/
    2872: PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
    2873: {
    2874:   PetscInt       size, g;

    2880:   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);
    2881:   *off = 0;
    2882:   for (g = 0; g < f; ++g) {
    2883:     PetscDSGetFieldSize(prob, g, &size);
    2884:     *off += size;
    2885:   }
    2886:   return(0);
    2887: }

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

    2892:   Not collective

    2894:   Input Parameter:
    2895: . prob - The PetscDS object

    2897:   Output Parameter:
    2898: . dimensions - The number of dimensions

    2900:   Level: beginner

    2902: .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
    2903: @*/
    2904: PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
    2905: {

    2910:   PetscDSSetUp(prob);
    2912:   *dimensions = prob->Nb;
    2913:   return(0);
    2914: }

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

    2919:   Not collective

    2921:   Input Parameter:
    2922: . prob - The PetscDS object

    2924:   Output Parameter:
    2925: . components - The number of components

    2927:   Level: beginner

    2929: .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
    2930: @*/
    2931: PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
    2932: {

    2937:   PetscDSSetUp(prob);
    2939:   *components = prob->Nc;
    2940:   return(0);
    2941: }

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

    2946:   Not collective

    2948:   Input Parameters:
    2949: + prob - The PetscDS object
    2950: - f - The field number

    2952:   Output Parameter:
    2953: . off - The offset

    2955:   Level: beginner

    2957: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    2958: @*/
    2959: PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
    2960: {

    2966:   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);
    2967:   PetscDSSetUp(prob);
    2968:   *off = prob->off[f];
    2969:   return(0);
    2970: }

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

    2975:   Not collective

    2977:   Input Parameter:
    2978: . prob - The PetscDS object

    2980:   Output Parameter:
    2981: . offsets - The offsets

    2983:   Level: beginner

    2985: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    2986: @*/
    2987: PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
    2988: {

    2994:   PetscDSSetUp(prob);
    2995:   *offsets = prob->off;
    2996:   return(0);
    2997: }

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

    3002:   Not collective

    3004:   Input Parameter:
    3005: . prob - The PetscDS object

    3007:   Output Parameter:
    3008: . offsets - The offsets

    3010:   Level: beginner

    3012: .seealso: PetscDSGetNumFields(), PetscDSCreate()
    3013: @*/
    3014: PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
    3015: {

    3021:   PetscDSSetUp(prob);
    3022:   *offsets = prob->offDer;
    3023:   return(0);
    3024: }

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

    3029:   Not collective

    3031:   Input Parameter:
    3032: . prob - The PetscDS object

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

    3037:   Level: intermediate

    3039: .seealso: PetscDSCreate()
    3040: @*/
    3041: PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[])
    3042: {

    3048:   PetscDSSetUp(prob);
    3049:   *T = prob->T;
    3050:   return(0);
    3051: }

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

    3056:   Not collective

    3058:   Input Parameter:
    3059: . prob - The PetscDS object

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

    3064:   Level: intermediate

    3066: .seealso: PetscDSGetTabulation(), PetscDSCreate()
    3067: @*/
    3068: PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
    3069: {

    3075:   PetscDSSetUp(prob);
    3076:   *Tf = prob->Tf;
    3077:   return(0);
    3078: }

    3080: PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
    3081: {

    3086:   PetscDSSetUp(prob);
    3090:   return(0);
    3091: }

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

    3099:   PetscDSSetUp(prob);
    3106:   return(0);
    3107: }

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

    3115:   PetscDSSetUp(prob);
    3121:   return(0);
    3122: }

    3124: /*@C
    3125:   PetscDSAddBoundary - Add a boundary condition to the model. The pointwise functions are used to provide boundary values for essential boundary conditions. In FEM, they are acting upon by dual basis functionals to generate FEM coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary integrals should be performaed, using the kernels from PetscDSSetBdResidual().

    3127:   Collective on ds

    3129:   Input Parameters:
    3130: + ds       - The PetscDS object
    3131: . type     - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    3132: . name     - The BC name
    3133: . label    - The label defining constrained points
    3134: . Nv       - The number of DMLabel values for constrained points
    3135: . values   - An array of label values for constrained points
    3136: . field    - The field to constrain
    3137: . Nc       - The number of constrained field components (0 will constrain all fields)
    3138: . comps    - An array of constrained component numbers
    3139: . bcFunc   - A pointwise function giving boundary values
    3140: . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
    3141: - ctx      - An optional user context for bcFunc

    3143:   Output Parameters:
    3144: - bd       - The boundary number

    3146:   Options Database Keys:
    3147: + -bc_<boundary name> <num> - Overrides the boundary ids
    3148: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    3150:   Note:
    3151:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

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

    3155:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

    3157: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    3158: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    3159: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    3160: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

    3162: + dim - the spatial dimension
    3163: . Nf - the number of fields
    3164: . uOff - the offset into u[] and u_t[] for each field
    3165: . uOff_x - the offset into u_x[] for each field
    3166: . u - each field evaluated at the current point
    3167: . u_t - the time derivative of each field evaluated at the current point
    3168: . u_x - the gradient of each field evaluated at the current point
    3169: . aOff - the offset into a[] and a_t[] for each auxiliary field
    3170: . aOff_x - the offset into a_x[] for each auxiliary field
    3171: . a - each auxiliary field evaluated at the current point
    3172: . a_t - the time derivative of each auxiliary field evaluated at the current point
    3173: . a_x - the gradient of auxiliary each field evaluated at the current point
    3174: . t - current time
    3175: . x - coordinates of the current point
    3176: . numConstants - number of constant parameters
    3177: . constants - constant parameters
    3178: - bcval - output values at the current point

    3180:   Level: developer

    3182: .seealso: PetscDSAddBoundaryByName(), PetscDSGetBoundary(), PetscDSSetResidual(), PetscDSSetBdResidual()
    3183: @*/
    3184: PetscErrorCode PetscDSAddBoundary(PetscDS ds, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
    3185: {
    3186:   DSBoundary     head = ds->boundary, b;
    3187:   PetscInt       n    = 0;
    3188:   const char    *lname;

    3199:   if (Nc > 0) {
    3200:     PetscInt *fcomps;
    3201:     PetscInt  c;

    3203:     PetscDSGetComponents(ds, &fcomps);
    3204:     if (Nc > fcomps[field]) SETERRQ3(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_OUTOFRANGE, "Number of constrained components %D > %D components for field %D", Nc, fcomps[field], field);
    3205:     for (c = 0; c < Nc; ++c) {
    3206:       if (comps[c] < 0 || comps[c] >= fcomps[field]) SETERRQ4(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_OUTOFRANGE, "Constrained component[%D] %D not in [0, %D) components for field %D", c, comps[c], fcomps[field], field);
    3207:     }
    3208:   }
    3209:   PetscNew(&b);
    3210:   PetscStrallocpy(name, (char **) &b->name);
    3211:   PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf);
    3212:   PetscWeakFormSetNumFields(b->wf, ds->Nf);
    3213:   PetscMalloc1(Nv, &b->values);
    3214:   if (Nv) {PetscArraycpy(b->values, values, Nv);}
    3215:   PetscMalloc1(Nc, &b->comps);
    3216:   if (Nc) {PetscArraycpy(b->comps, comps, Nc);}
    3217:   PetscObjectGetName((PetscObject) label, &lname);
    3218:   PetscStrallocpy(lname, (char **) &b->lname);
    3219:   b->type   = type;
    3220:   b->label  = label;
    3221:   b->Nv     = Nv;
    3222:   b->field  = field;
    3223:   b->Nc     = Nc;
    3224:   b->func   = bcFunc;
    3225:   b->func_t = bcFunc_t;
    3226:   b->ctx    = ctx;
    3227:   b->next   = NULL;
    3228:   /* Append to linked list so that we can preserve the order */
    3229:   if (!head) ds->boundary = b;
    3230:   while (head) {
    3231:     if (!head->next) {
    3232:       head->next = b;
    3233:       head       = b;
    3234:     }
    3235:     head = head->next;
    3236:     ++n;
    3237:   }
    3239:   return(0);
    3240: }

    3242: /*@C
    3243:   PetscDSAddBoundaryByName - Add a boundary condition to the model. The pointwise functions are used to provide boundary values for essential boundary conditions. In FEM, they are acting upon by dual basis functionals to generate FEM coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary integrals should be performaed, using the kernels from PetscDSSetBdResidual().

    3245:   Collective on ds

    3247:   Input Parameters:
    3248: + ds       - The PetscDS object
    3249: . type     - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    3250: . name     - The BC name
    3251: . lname    - The naem of the label defining constrained points
    3252: . Nv       - The number of DMLabel values for constrained points
    3253: . values   - An array of label values for constrained points
    3254: . field    - The field to constrain
    3255: . Nc       - The number of constrained field components (0 will constrain all fields)
    3256: . comps    - An array of constrained component numbers
    3257: . bcFunc   - A pointwise function giving boundary values
    3258: . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
    3259: - ctx      - An optional user context for bcFunc

    3261:   Output Parameters:
    3262: - bd       - The boundary number

    3264:   Options Database Keys:
    3265: + -bc_<boundary name> <num> - Overrides the boundary ids
    3266: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    3268:   Note:
    3269:   This function should only be used with DMForest currently, since labels cannot be defined before the underlygin Plex is built.

    3271:   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:

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

    3275:   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:

    3277: $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
    3278: $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
    3279: $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
    3280: $        PetscReal time, const PetscReal x[], PetscScalar bcval[])

    3282: + dim - the spatial dimension
    3283: . Nf - the number of fields
    3284: . uOff - the offset into u[] and u_t[] for each field
    3285: . uOff_x - the offset into u_x[] for each field
    3286: . u - each field evaluated at the current point
    3287: . u_t - the time derivative of each field evaluated at the current point
    3288: . u_x - the gradient of each field evaluated at the current point
    3289: . aOff - the offset into a[] and a_t[] for each auxiliary field
    3290: . aOff_x - the offset into a_x[] for each auxiliary field
    3291: . a - each auxiliary field evaluated at the current point
    3292: . a_t - the time derivative of each auxiliary field evaluated at the current point
    3293: . a_x - the gradient of auxiliary each field evaluated at the current point
    3294: . t - current time
    3295: . x - coordinates of the current point
    3296: . numConstants - number of constant parameters
    3297: . constants - constant parameters
    3298: - bcval - output values at the current point

    3300:   Level: developer

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

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

    3350: /*@C
    3351:   PetscDSUpdateBoundary - Change a boundary condition for the model. The pointwise functions are used to provide boundary values for essential boundary conditions. In FEM, they are acting upon by dual basis functionals to generate FEM coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary integrals should be performaed, using the kernels from PetscDSSetBdResidual().

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

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

    3371:   Level: developer

    3373: .seealso: PetscDSAddBoundary(), PetscDSGetBoundary(), PetscDSGetNumBoundary()
    3374: @*/
    3375: PetscErrorCode PetscDSUpdateBoundary(PetscDS ds, PetscInt bd, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx)
    3376: {
    3377:   DSBoundary     b = ds->boundary;
    3378:   PetscInt       n = 0;

    3383:   while (b) {
    3384:     if (n == bd) break;
    3385:     b = b->next;
    3386:     ++n;
    3387:   }
    3388:   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
    3389:   if (name) {
    3390:     PetscFree(b->name);
    3391:     PetscStrallocpy(name, (char **) &b->name);
    3392:   }
    3393:   b->type = type;
    3394:   if (label) {
    3395:     const char *name;

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

    3421: /*@
    3422:   PetscDSGetNumBoundary - Get the number of registered BC

    3424:   Input Parameters:
    3425: . ds - The PetscDS object

    3427:   Output Parameters:
    3428: . numBd - The number of BC

    3430:   Level: intermediate

    3432: .seealso: PetscDSAddBoundary(), PetscDSGetBoundary()
    3433: @*/
    3434: PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
    3435: {
    3436:   DSBoundary b = ds->boundary;

    3441:   *numBd = 0;
    3442:   while (b) {++(*numBd); b = b->next;}
    3443:   return(0);
    3444: }

    3446: /*@C
    3447:   PetscDSGetBoundary - Gets a boundary condition to the model

    3449:   Input Parameters:
    3450: + ds          - The PetscDS object
    3451: - bd          - The BC number

    3453:   Output Parameters:
    3454: + wf       - The PetscWeakForm holding the pointwise functions
    3455: . type     - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
    3456: . name     - The BC name
    3457: . label    - The label defining constrained points
    3458: . Nv       - The number of DMLabel ids for constrained points
    3459: . values   - An array of ids for constrained points
    3460: . field    - The field to constrain
    3461: . Nc       - The number of constrained field components
    3462: . comps    - An array of constrained component numbers
    3463: . bcFunc   - A pointwise function giving boundary values
    3464: . bcFunc_t - A pointwise function giving the time derivative of the boundary values
    3465: - ctx      - An optional user context for bcFunc

    3467:   Options Database Keys:
    3468: + -bc_<boundary name> <num> - Overrides the boundary ids
    3469: - -bc_<boundary name>_comp <num> - Overrides the boundary components

    3471:   Level: developer

    3473: .seealso: PetscDSAddBoundary()
    3474: @*/
    3475: PetscErrorCode PetscDSGetBoundary(PetscDS ds, PetscInt bd, PetscWeakForm *wf, DMBoundaryConditionType *type, const char *name[], DMLabel *label, PetscInt *Nv, const PetscInt *values[], PetscInt *field, PetscInt *Nc, const PetscInt *comps[], void (**func)(void), void (**func_t)(void), void **ctx)
    3476: {
    3477:   DSBoundary b = ds->boundary;
    3478:   PetscInt   n = 0;

    3482:   while (b) {
    3483:     if (n == bd) break;
    3484:     b = b->next;
    3485:     ++n;
    3486:   }
    3487:   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
    3488:   if (wf) {
    3490:     *wf = b->wf;
    3491:   }
    3492:   if (type) {
    3494:     *type = b->type;
    3495:   }
    3496:   if (name) {
    3498:     *name = b->name;
    3499:   }
    3500:   if (label) {
    3502:     *label = b->label;
    3503:   }
    3504:   if (Nv) {
    3506:     *Nv = b->Nv;
    3507:   }
    3508:   if (values) {
    3510:     *values = b->values;
    3511:   }
    3512:   if (field) {
    3514:     *field = b->field;
    3515:   }
    3516:   if (Nc) {
    3518:     *Nc = b->Nc;
    3519:   }
    3520:   if (comps) {
    3522:     *comps = b->comps;
    3523:   }
    3524:   if (func) {
    3526:     *func = b->func;
    3527:   }
    3528:   if (func_t) {
    3530:     *func_t = b->func_t;
    3531:   }
    3532:   if (ctx) {
    3534:     *ctx = b->ctx;
    3535:   }
    3536:   return(0);
    3537: }

    3539: static PetscErrorCode DSBoundaryDuplicate_Internal(DSBoundary b, DSBoundary *bNew)
    3540: {

    3544:   PetscNew(bNew);
    3545:   PetscWeakFormCreate(PETSC_COMM_SELF, &(*bNew)->wf);
    3546:   PetscWeakFormCopy(b->wf, (*bNew)->wf);
    3547:   PetscStrallocpy(b->name,(char **) &((*bNew)->name));
    3548:   PetscStrallocpy(b->lname,(char **) &((*bNew)->lname));
    3549:   (*bNew)->type   = b->type;
    3550:   (*bNew)->label  = b->label;
    3551:   (*bNew)->Nv     = b->Nv;
    3552:   PetscMalloc1(b->Nv, &(*bNew)->values);
    3553:   PetscArraycpy((*bNew)->values, b->values, b->Nv);
    3554:   (*bNew)->field  = b->field;
    3555:   (*bNew)->Nc     = b->Nc;
    3556:   PetscMalloc1(b->Nc, &(*bNew)->comps);
    3557:   PetscArraycpy((*bNew)->comps, b->comps, b->Nc);
    3558:   (*bNew)->func   = b->func;
    3559:   (*bNew)->func_t = b->func_t;
    3560:   (*bNew)->ctx    = b->ctx;
    3561:   return(0);
    3562: }

    3564: /*@
    3565:   PetscDSCopyBoundary - Copy all boundary condition objects to the new problem

    3567:   Not collective

    3569:   Input Parameters:
    3570: + ds        - The source PetscDS object
    3571: . numFields - The number of selected fields, or PETSC_DEFAULT for all fields
    3572: - fields    - The selected fields, or NULL for all fields

    3574:   Output Parameter:
    3575: . newds     - The target PetscDS, now with a copy of the boundary conditions

    3577:   Level: intermediate

    3579: .seealso: PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    3580: @*/
    3581: PetscErrorCode PetscDSCopyBoundary(PetscDS ds, PetscInt numFields, const PetscInt fields[], PetscDS newds)
    3582: {
    3583:   DSBoundary     b, *lastnext;

    3589:   if (ds == newds) return(0);
    3590:   PetscDSDestroyBoundary(newds);
    3591:   lastnext = &(newds->boundary);
    3592:   for (b = ds->boundary; b; b = b->next) {
    3593:     DSBoundary bNew;
    3594:     PetscInt   fieldNew = -1;

    3596:     if (numFields > 0 && fields) {
    3597:       PetscInt f;

    3599:       for (f = 0; f < numFields; ++f) if (b->field == fields[f]) break;
    3600:       if (f == numFields) continue;
    3601:       fieldNew = f;
    3602:     }
    3603:     DSBoundaryDuplicate_Internal(b, &bNew);
    3604:     bNew->field = fieldNew < 0 ? b->field : fieldNew;
    3605:     *lastnext = bNew;
    3606:     lastnext  = &(bNew->next);
    3607:   }
    3608:   return(0);
    3609: }

    3611: /*@
    3612:   PetscDSDestroyBoundary - Remove all DMBoundary objects from the PetscDS

    3614:   Not collective

    3616:   Input Parameter:
    3617: . ds - The PetscDS object

    3619:   Level: intermediate

    3621: .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations()
    3622: @*/
    3623: PetscErrorCode PetscDSDestroyBoundary(PetscDS ds)
    3624: {
    3625:   DSBoundary     next = ds->boundary;

    3629:   while (next) {
    3630:     DSBoundary b = next;

    3632:     next = b->next;
    3633:     PetscWeakFormDestroy(&b->wf);
    3634:     PetscFree(b->name);
    3635:     PetscFree(b->lname);
    3636:     PetscFree(b->values);
    3637:     PetscFree(b->comps);
    3638:     PetscFree(b);
    3639:   }
    3640:   return(0);
    3641: }

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

    3646:   Not collective

    3648:   Input Parameters:
    3649: + prob - The PetscDS object
    3650: . numFields - Number of new fields
    3651: - fields - Old field number for each new field

    3653:   Output Parameter:
    3654: . newprob - The PetscDS copy

    3656:   Level: intermediate

    3658: .seealso: PetscDSSelectEquations(), PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    3659: @*/
    3660: PetscErrorCode PetscDSSelectDiscretizations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
    3661: {
    3662:   PetscInt       Nf, Nfn, fn;

    3669:   PetscDSGetNumFields(prob, &Nf);
    3670:   PetscDSGetNumFields(newprob, &Nfn);
    3671:   numFields = numFields < 0 ? Nf : numFields;
    3672:   for (fn = 0; fn < numFields; ++fn) {
    3673:     const PetscInt f = fields ? fields[fn] : fn;
    3674:     PetscObject    disc;

    3676:     if (f >= Nf) continue;
    3677:     PetscDSGetDiscretization(prob, f, &disc);
    3678:     PetscDSSetDiscretization(newprob, fn, disc);
    3679:   }
    3680:   return(0);
    3681: }

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

    3686:   Not collective

    3688:   Input Parameters:
    3689: + prob - The PetscDS object
    3690: . numFields - Number of new fields
    3691: - fields - Old field number for each new field

    3693:   Output Parameter:
    3694: . newprob - The PetscDS copy

    3696:   Level: intermediate

    3698: .seealso: PetscDSSelectDiscretizations(), PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    3699: @*/
    3700: PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
    3701: {
    3702:   PetscInt       Nf, Nfn, fn, gn;

    3709:   PetscDSGetNumFields(prob, &Nf);
    3710:   PetscDSGetNumFields(newprob, &Nfn);
    3711:   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);
    3712:   for (fn = 0; fn < numFields; ++fn) {
    3713:     const PetscInt   f = fields ? fields[fn] : fn;
    3714:     PetscPointFunc   obj;
    3715:     PetscPointFunc   f0, f1;
    3716:     PetscBdPointFunc f0Bd, f1Bd;
    3717:     PetscRiemannFunc r;

    3719:     if (f >= Nf) continue;
    3720:     PetscDSGetObjective(prob, f, &obj);
    3721:     PetscDSGetResidual(prob, f, &f0, &f1);
    3722:     PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd);
    3723:     PetscDSGetRiemannSolver(prob, f, &r);
    3724:     PetscDSSetObjective(newprob, fn, obj);
    3725:     PetscDSSetResidual(newprob, fn, f0, f1);
    3726:     PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd);
    3727:     PetscDSSetRiemannSolver(newprob, fn, r);
    3728:     for (gn = 0; gn < numFields; ++gn) {
    3729:       const PetscInt  g = fields ? fields[gn] : gn;
    3730:       PetscPointJac   g0, g1, g2, g3;
    3731:       PetscPointJac   g0p, g1p, g2p, g3p;
    3732:       PetscBdPointJac g0Bd, g1Bd, g2Bd, g3Bd;

    3734:       if (g >= Nf) continue;
    3735:       PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3);
    3736:       PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p);
    3737:       PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd);
    3738:       PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3);
    3739:       PetscDSSetJacobianPreconditioner(newprob, fn, gn, g0p, g1p, g2p, g3p);
    3740:       PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd);
    3741:     }
    3742:   }
    3743:   return(0);
    3744: }

    3746: /*@
    3747:   PetscDSCopyEquations - Copy all pointwise function pointers to the new problem

    3749:   Not collective

    3751:   Input Parameter:
    3752: . prob - The PetscDS object

    3754:   Output Parameter:
    3755: . newprob - The PetscDS copy

    3757:   Level: intermediate

    3759: .seealso: PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    3760: @*/
    3761: PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
    3762: {
    3763:   PetscWeakForm  wf, newwf;
    3764:   PetscInt       Nf, Ng;

    3770:   PetscDSGetNumFields(prob, &Nf);
    3771:   PetscDSGetNumFields(newprob, &Ng);
    3772:   if (Nf != Ng) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %D != %D", Nf, Ng);
    3773:   PetscDSGetWeakForm(prob, &wf);
    3774:   PetscDSGetWeakForm(newprob, &newwf);
    3775:   PetscWeakFormCopy(wf, newwf);
    3776:   return(0);
    3777: }

    3779: /*@
    3780:   PetscDSCopyConstants - Copy all constants to the new problem

    3782:   Not collective

    3784:   Input Parameter:
    3785: . prob - The PetscDS object

    3787:   Output Parameter:
    3788: . newprob - The PetscDS copy

    3790:   Level: intermediate

    3792: .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    3793: @*/
    3794: PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
    3795: {
    3796:   PetscInt           Nc;
    3797:   const PetscScalar *constants;
    3798:   PetscErrorCode     ierr;

    3803:   PetscDSGetConstants(prob, &Nc, &constants);
    3804:   PetscDSSetConstants(newprob, Nc, (PetscScalar *) constants);
    3805:   return(0);
    3806: }

    3808: /*@
    3809:   PetscDSCopyExactSolutions - Copy all exact solutions to the new problem

    3811:   Not collective

    3813:   Input Parameter:
    3814: . ds - The PetscDS object

    3816:   Output Parameter:
    3817: . newds - The PetscDS copy

    3819:   Level: intermediate

    3821: .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
    3822: @*/
    3823: PetscErrorCode PetscDSCopyExactSolutions(PetscDS ds, PetscDS newds)
    3824: {
    3825:   PetscSimplePointFunc sol;
    3826:   void                *ctx;
    3827:   PetscInt             Nf, f;
    3828:   PetscErrorCode       ierr;

    3833:   PetscDSGetNumFields(ds, &Nf);
    3834:   for (f = 0; f < Nf; ++f) {
    3835:     PetscDSGetExactSolution(ds,    f, &sol, &ctx);
    3836:     PetscDSSetExactSolution(newds, f,  sol,  ctx);
    3837:     PetscDSGetExactSolutionTimeDerivative(ds,    f, &sol, &ctx);
    3838:     PetscDSSetExactSolutionTimeDerivative(newds, f,  sol,  ctx);
    3839:   }
    3840:   return(0);
    3841: }

    3843: PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
    3844: {
    3845:   PetscInt       dim, Nf, f;

    3851:   if (height == 0) {*subprob = prob; return(0);}
    3852:   PetscDSGetNumFields(prob, &Nf);
    3853:   PetscDSGetSpatialDimension(prob, &dim);
    3854:   if (height > dim) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %D], not %D", dim, height);
    3855:   if (!prob->subprobs) {PetscCalloc1(dim, &prob->subprobs);}
    3856:   if (!prob->subprobs[height-1]) {
    3857:     PetscInt cdim;

    3859:     PetscDSCreate(PetscObjectComm((PetscObject) prob), &prob->subprobs[height-1]);
    3860:     PetscDSGetCoordinateDimension(prob, &cdim);
    3861:     PetscDSSetCoordinateDimension(prob->subprobs[height-1], cdim);
    3862:     for (f = 0; f < Nf; ++f) {
    3863:       PetscFE      subfe;
    3864:       PetscObject  obj;
    3865:       PetscClassId id;

    3867:       PetscDSGetDiscretization(prob, f, &obj);
    3868:       PetscObjectGetClassId(obj, &id);
    3869:       if (id == PETSCFE_CLASSID) {PetscFEGetHeightSubspace((PetscFE) obj, height, &subfe);}
    3870:       else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %d", f);
    3871:       PetscDSSetDiscretization(prob->subprobs[height-1], f, (PetscObject) subfe);
    3872:     }
    3873:   }
    3874:   *subprob = prob->subprobs[height-1];
    3875:   return(0);
    3876: }

    3878: PetscErrorCode PetscDSGetDiscType_Internal(PetscDS ds, PetscInt f, PetscDiscType *disctype)
    3879: {
    3880:   PetscObject    obj;
    3881:   PetscClassId   id;
    3882:   PetscInt       Nf;

    3888:   *disctype = PETSC_DISC_NONE;
    3889:   PetscDSGetNumFields(ds, &Nf);
    3890:   if (f >= Nf) SETERRQ2(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_SIZ, "Field %D must be in [0, %D)", f, Nf);
    3891:   PetscDSGetDiscretization(ds, f, &obj);
    3892:   if (obj) {
    3893:     PetscObjectGetClassId(obj, &id);
    3894:     if (id == PETSCFE_CLASSID) *disctype = PETSC_DISC_FE;
    3895:     else                       *disctype = PETSC_DISC_FV;
    3896:   }
    3897:   return(0);
    3898: }

    3900: static PetscErrorCode PetscDSDestroy_Basic(PetscDS ds)
    3901: {

    3905:   PetscFree(ds->data);
    3906:   return(0);
    3907: }

    3909: static PetscErrorCode PetscDSInitialize_Basic(PetscDS ds)
    3910: {
    3912:   ds->ops->setfromoptions = NULL;
    3913:   ds->ops->setup          = NULL;
    3914:   ds->ops->view           = NULL;
    3915:   ds->ops->destroy        = PetscDSDestroy_Basic;
    3916:   return(0);
    3917: }

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

    3922:   Level: intermediate

    3924: .seealso: PetscDSType, PetscDSCreate(), PetscDSSetType()
    3925: M*/

    3927: PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS ds)
    3928: {
    3929:   PetscDS_Basic *b;

    3934:   PetscNewLog(ds, &b);
    3935:   ds->data = b;

    3937:   PetscDSInitialize_Basic(ds);
    3938:   return(0);
    3939: }