xref: /petsc/src/dm/dt/interface/dtds.c (revision c3b5f7ba6bc5ce25a01a67bb37ba5d34b02bbbd7)
1 #include <petsc/private/petscdsimpl.h> /*I "petscds.h" I*/
2 
3 PetscClassId PETSCDS_CLASSID = 0;
4 
5 PetscFunctionList PetscDSList              = NULL;
6 PetscBool         PetscDSRegisterAllCalled = PETSC_FALSE;
7 
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.
11 
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.
14 
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 */
20 
21 /*@C
22   PetscDSRegister - Adds a new PetscDS implementation
23 
24   Not Collective
25 
26   Input Parameters:
27 + name        - The name of a new user-defined creation routine
28 - create_func - The creation routine itself
29 
30   Notes:
31   PetscDSRegister() may be called multiple times to add several user-defined PetscDSs
32 
33   Sample usage:
34 .vb
35     PetscDSRegister("my_ds", MyPetscDSCreate);
36 .ve
37 
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
47 
48   Level: advanced
49 
50    Not available from Fortran
51 
52 .seealso: PetscDSRegisterAll(), PetscDSRegisterDestroy()
53 
54 @*/
55 PetscErrorCode PetscDSRegister(const char sname[], PetscErrorCode (*function)(PetscDS))
56 {
57   PetscFunctionBegin;
58   PetscCall(PetscFunctionListAdd(&PetscDSList, sname, function));
59   PetscFunctionReturn(0);
60 }
61 
62 /*@C
63   PetscDSSetType - Builds a particular PetscDS
64 
65   Collective on prob
66 
67   Input Parameters:
68 + prob - The PetscDS object
69 - name - The kind of system
70 
71   Options Database Key:
72 . -petscds_type <type> - Sets the PetscDS type; use -help for a list of available types
73 
74   Level: intermediate
75 
76    Not available from Fortran
77 
78 .seealso: PetscDSGetType(), PetscDSCreate()
79 @*/
80 PetscErrorCode PetscDSSetType(PetscDS prob, PetscDSType name)
81 {
82   PetscErrorCode (*r)(PetscDS);
83   PetscBool      match;
84 
85   PetscFunctionBegin;
86   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
87   PetscCall(PetscObjectTypeCompare((PetscObject) prob, name, &match));
88   if (match) PetscFunctionReturn(0);
89 
90   PetscCall(PetscDSRegisterAll());
91   PetscCall(PetscFunctionListFind(PetscDSList, name, &r));
92   PetscCheck(r,PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDS type: %s", name);
93 
94   if (prob->ops->destroy) {
95     PetscCall((*prob->ops->destroy)(prob));
96     prob->ops->destroy = NULL;
97   }
98   PetscCall((*r)(prob));
99   PetscCall(PetscObjectChangeTypeName((PetscObject) prob, name));
100   PetscFunctionReturn(0);
101 }
102 
103 /*@C
104   PetscDSGetType - Gets the PetscDS type name (as a string) from the object.
105 
106   Not Collective
107 
108   Input Parameter:
109 . prob  - The PetscDS
110 
111   Output Parameter:
112 . name - The PetscDS type name
113 
114   Level: intermediate
115 
116    Not available from Fortran
117 
118 .seealso: PetscDSSetType(), PetscDSCreate()
119 @*/
120 PetscErrorCode PetscDSGetType(PetscDS prob, PetscDSType *name)
121 {
122   PetscFunctionBegin;
123   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
124   PetscValidPointer(name, 2);
125   PetscCall(PetscDSRegisterAll());
126   *name = ((PetscObject) prob)->type_name;
127   PetscFunctionReturn(0);
128 }
129 
130 static PetscErrorCode PetscDSView_Ascii(PetscDS ds, PetscViewer viewer)
131 {
132   PetscViewerFormat  format;
133   const PetscScalar *constants;
134   PetscInt           Nf, numConstants, f;
135 
136   PetscFunctionBegin;
137   PetscCall(PetscDSGetNumFields(ds, &Nf));
138   PetscCall(PetscViewerGetFormat(viewer, &format));
139   PetscCall(PetscViewerASCIIPrintf(viewer, "Discrete System with %d fields\n", Nf));
140   PetscCall(PetscViewerASCIIPushTab(viewer));
141   PetscCall(PetscViewerASCIIPrintf(viewer, "  cell total dim %D total comp %D\n", ds->totDim, ds->totComp));
142   if (ds->isCohesive) PetscCall(PetscViewerASCIIPrintf(viewer, "  cohesive cell\n"));
143   for (f = 0; f < Nf; ++f) {
144     DSBoundary      b;
145     PetscObject     obj;
146     PetscClassId    id;
147     PetscQuadrature q;
148     const char     *name;
149     PetscInt        Nc, Nq, Nqc;
150 
151     PetscCall(PetscDSGetDiscretization(ds, f, &obj));
152     PetscCall(PetscObjectGetClassId(obj, &id));
153     PetscCall(PetscObjectGetName(obj, &name));
154     PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s", name ? name : "<unknown>"));
155     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
156     if (id == PETSCFE_CLASSID)      {
157       PetscCall(PetscFEGetNumComponents((PetscFE) obj, &Nc));
158       PetscCall(PetscFEGetQuadrature((PetscFE) obj, &q));
159       PetscCall(PetscViewerASCIIPrintf(viewer, " FEM"));
160     } else if (id == PETSCFV_CLASSID) {
161       PetscCall(PetscFVGetNumComponents((PetscFV) obj, &Nc));
162       PetscCall(PetscFVGetQuadrature((PetscFV) obj, &q));
163       PetscCall(PetscViewerASCIIPrintf(viewer, " FVM"));
164     }
165     else SETERRQ(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f);
166     if (Nc > 1) PetscCall(PetscViewerASCIIPrintf(viewer, " %D components", Nc));
167     else        PetscCall(PetscViewerASCIIPrintf(viewer, " %D component ", Nc));
168     if (ds->implicit[f]) PetscCall(PetscViewerASCIIPrintf(viewer, " (implicit)"));
169     else                 PetscCall(PetscViewerASCIIPrintf(viewer, " (explicit)"));
170     if (q) {
171       PetscCall(PetscQuadratureGetData(q, NULL, &Nqc, &Nq, NULL, NULL));
172       PetscCall(PetscViewerASCIIPrintf(viewer, " (Nq %D Nqc %D)", Nq, Nqc));
173     }
174     PetscCall(PetscViewerASCIIPrintf(viewer, " %D-jet", ds->jetDegree[f]));
175     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
176     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
177     PetscCall(PetscViewerASCIIPushTab(viewer));
178     if (id == PETSCFE_CLASSID)      PetscCall(PetscFEView((PetscFE) obj, viewer));
179     else if (id == PETSCFV_CLASSID) PetscCall(PetscFVView((PetscFV) obj, viewer));
180     PetscCall(PetscViewerASCIIPopTab(viewer));
181 
182     for (b = ds->boundary; b; b = b->next) {
183       char     *name;
184       PetscInt  c, i;
185 
186       if (b->field != f) continue;
187       PetscCall(PetscViewerASCIIPushTab(viewer));
188       PetscCall(PetscViewerASCIIPrintf(viewer, "Boundary %s (%s) %s\n", b->name, b->lname, DMBoundaryConditionTypes[b->type]));
189       if (!b->Nc) {
190         PetscCall(PetscViewerASCIIPrintf(viewer, "  all components\n"));
191       } else {
192         PetscCall(PetscViewerASCIIPrintf(viewer, "  components: "));
193         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
194         for (c = 0; c < b->Nc; ++c) {
195           if (c > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
196           PetscCall(PetscViewerASCIIPrintf(viewer, "%D", b->comps[c]));
197         }
198         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
199         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
200       }
201       PetscCall(PetscViewerASCIIPrintf(viewer, "  values: "));
202       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
203       for (i = 0; i < b->Nv; ++i) {
204         if (i > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
205         PetscCall(PetscViewerASCIIPrintf(viewer, "%D", b->values[i]));
206       }
207       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
208       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
209       if (b->func) {
210         PetscCall(PetscDLAddr(b->func, &name));
211         if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "  func: %s\n", name));
212         else      PetscCall(PetscViewerASCIIPrintf(viewer, "  func: %p\n", b->func));
213         PetscCall(PetscFree(name));
214       }
215       if (b->func_t) {
216         PetscCall(PetscDLAddr(b->func_t, &name));
217         if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "  func_t: %s\n", name));
218         else      PetscCall(PetscViewerASCIIPrintf(viewer, "  func_t: %p\n", b->func_t));
219         PetscCall(PetscFree(name));
220       }
221       PetscCall(PetscWeakFormView(b->wf, viewer));
222       PetscCall(PetscViewerASCIIPopTab(viewer));
223     }
224   }
225   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
226   if (numConstants) {
227     PetscCall(PetscViewerASCIIPrintf(viewer, "%D constants\n", numConstants));
228     PetscCall(PetscViewerASCIIPushTab(viewer));
229     for (f = 0; f < numConstants; ++f) PetscCall(PetscViewerASCIIPrintf(viewer, "%g\n", (double) PetscRealPart(constants[f])));
230     PetscCall(PetscViewerASCIIPopTab(viewer));
231   }
232   PetscCall(PetscWeakFormView(ds->wf, viewer));
233   PetscCall(PetscViewerASCIIPopTab(viewer));
234   PetscFunctionReturn(0);
235 }
236 
237 /*@C
238    PetscDSViewFromOptions - View from Options
239 
240    Collective on PetscDS
241 
242    Input Parameters:
243 +  A - the PetscDS object
244 .  obj - Optional object
245 -  name - command line option
246 
247    Level: intermediate
248 .seealso:  PetscDS, PetscDSView, PetscObjectViewFromOptions(), PetscDSCreate()
249 @*/
250 PetscErrorCode  PetscDSViewFromOptions(PetscDS A,PetscObject obj,const char name[])
251 {
252   PetscFunctionBegin;
253   PetscValidHeaderSpecific(A,PETSCDS_CLASSID,1);
254   PetscCall(PetscObjectViewFromOptions((PetscObject)A,obj,name));
255   PetscFunctionReturn(0);
256 }
257 
258 /*@C
259   PetscDSView - Views a PetscDS
260 
261   Collective on prob
262 
263   Input Parameters:
264 + prob - the PetscDS object to view
265 - v  - the viewer
266 
267   Level: developer
268 
269 .seealso PetscDSDestroy()
270 @*/
271 PetscErrorCode PetscDSView(PetscDS prob, PetscViewer v)
272 {
273   PetscBool      iascii;
274 
275   PetscFunctionBegin;
276   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
277   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) prob), &v));
278   else    {PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);}
279   PetscCall(PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &iascii));
280   if (iascii) PetscCall(PetscDSView_Ascii(prob, v));
281   if (prob->ops->view) PetscCall((*prob->ops->view)(prob, v));
282   PetscFunctionReturn(0);
283 }
284 
285 /*@
286   PetscDSSetFromOptions - sets parameters in a PetscDS from the options database
287 
288   Collective on prob
289 
290   Input Parameter:
291 . prob - the PetscDS object to set options for
292 
293   Options Database:
294 + -petscds_type <type>     - Set the DS type
295 . -petscds_view <view opt> - View the DS
296 . -petscds_jac_pre         - Turn formation of a separate Jacobian preconditioner on or off
297 . -bc_<name> <ids>         - Specify a list of label ids for a boundary condition
298 - -bc_<name>_comp <comps>  - Specify a list of field components to constrain for a boundary condition
299 
300   Level: developer
301 
302 .seealso PetscDSView()
303 @*/
304 PetscErrorCode PetscDSSetFromOptions(PetscDS prob)
305 {
306   DSBoundary     b;
307   const char    *defaultType;
308   char           name[256];
309   PetscBool      flg;
310   PetscErrorCode ierr;
311 
312   PetscFunctionBegin;
313   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
314   if (!((PetscObject) prob)->type_name) {
315     defaultType = PETSCDSBASIC;
316   } else {
317     defaultType = ((PetscObject) prob)->type_name;
318   }
319   PetscCall(PetscDSRegisterAll());
320 
321   ierr = PetscObjectOptionsBegin((PetscObject) prob);PetscCall(ierr);
322   for (b = prob->boundary; b; b = b->next) {
323     char       optname[1024];
324     PetscInt   ids[1024], len = 1024;
325     PetscBool  flg;
326 
327     PetscCall(PetscSNPrintf(optname, sizeof(optname), "-bc_%s", b->name));
328     PetscCall(PetscMemzero(ids, sizeof(ids)));
329     PetscCall(PetscOptionsIntArray(optname, "List of boundary IDs", "", ids, &len, &flg));
330     if (flg) {
331       b->Nv = len;
332       PetscCall(PetscFree(b->values));
333       PetscCall(PetscMalloc1(len, &b->values));
334       PetscCall(PetscArraycpy(b->values, ids, len));
335       PetscCall(PetscWeakFormRewriteKeys(b->wf, b->label, len, b->values));
336     }
337     len = 1024;
338     PetscCall(PetscSNPrintf(optname, sizeof(optname), "-bc_%s_comp", b->name));
339     PetscCall(PetscMemzero(ids, sizeof(ids)));
340     PetscCall(PetscOptionsIntArray(optname, "List of boundary field components", "", ids, &len, &flg));
341     if (flg) {
342       b->Nc = len;
343       PetscCall(PetscFree(b->comps));
344       PetscCall(PetscMalloc1(len, &b->comps));
345       PetscCall(PetscArraycpy(b->comps, ids, len));
346     }
347   }
348   PetscCall(PetscOptionsFList("-petscds_type", "Discrete System", "PetscDSSetType", PetscDSList, defaultType, name, 256, &flg));
349   if (flg) {
350     PetscCall(PetscDSSetType(prob, name));
351   } else if (!((PetscObject) prob)->type_name) {
352     PetscCall(PetscDSSetType(prob, defaultType));
353   }
354   PetscCall(PetscOptionsBool("-petscds_jac_pre", "Discrete System", "PetscDSUseJacobianPreconditioner", prob->useJacPre, &prob->useJacPre, &flg));
355   if (prob->ops->setfromoptions) PetscCall((*prob->ops->setfromoptions)(prob));
356   /* process any options handlers added with PetscObjectAddOptionsHandler() */
357   PetscCall(PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) prob));
358   ierr = PetscOptionsEnd();PetscCall(ierr);
359   if (prob->Nf) PetscCall(PetscDSViewFromOptions(prob, NULL, "-petscds_view"));
360   PetscFunctionReturn(0);
361 }
362 
363 /*@C
364   PetscDSSetUp - Construct data structures for the PetscDS
365 
366   Collective on prob
367 
368   Input Parameter:
369 . prob - the PetscDS object to setup
370 
371   Level: developer
372 
373 .seealso PetscDSView(), PetscDSDestroy()
374 @*/
375 PetscErrorCode PetscDSSetUp(PetscDS prob)
376 {
377   const PetscInt Nf   = prob->Nf;
378   PetscBool      hasH = PETSC_FALSE;
379   PetscInt       dim, dimEmbed, NbMax = 0, NcMax = 0, NqMax = 0, NsMax = 1, f;
380   PetscErrorCode ierr;
381 
382   PetscFunctionBegin;
383   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
384   if (prob->setup) PetscFunctionReturn(0);
385   /* Calculate sizes */
386   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
387   PetscCall(PetscDSGetCoordinateDimension(prob, &dimEmbed));
388   prob->totDim = prob->totComp = 0;
389   PetscCall(PetscMalloc2(Nf,&prob->Nc,Nf,&prob->Nb));
390   PetscCall(PetscCalloc2(Nf+1,&prob->off,Nf+1,&prob->offDer));
391   PetscCall(PetscCalloc6(Nf+1,&prob->offCohesive[0],Nf+1,&prob->offCohesive[1],Nf+1,&prob->offCohesive[2],Nf+1,&prob->offDerCohesive[0],Nf+1,&prob->offDerCohesive[1],Nf+1,&prob->offDerCohesive[2]));
392   PetscCall(PetscMalloc2(Nf,&prob->T,Nf,&prob->Tf));
393   for (f = 0; f < Nf; ++f) {
394     PetscObject     obj;
395     PetscClassId    id;
396     PetscQuadrature q = NULL;
397     PetscInt        Nq = 0, Nb, Nc;
398 
399     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
400     if (prob->jetDegree[f] > 1) hasH = PETSC_TRUE;
401     if (!obj) {
402       /* Empty mesh */
403       Nb = Nc = 0;
404       prob->T[f] = prob->Tf[f] = NULL;
405     } else {
406       PetscCall(PetscObjectGetClassId(obj, &id));
407       if (id == PETSCFE_CLASSID)      {
408         PetscFE fe = (PetscFE) obj;
409 
410         PetscCall(PetscFEGetQuadrature(fe, &q));
411         PetscCall(PetscFEGetDimension(fe, &Nb));
412         PetscCall(PetscFEGetNumComponents(fe, &Nc));
413         PetscCall(PetscFEGetCellTabulation(fe, prob->jetDegree[f], &prob->T[f]));
414         PetscCall(PetscFEGetFaceTabulation(fe, prob->jetDegree[f], &prob->Tf[f]));
415       } else if (id == PETSCFV_CLASSID) {
416         PetscFV fv = (PetscFV) obj;
417 
418         PetscCall(PetscFVGetQuadrature(fv, &q));
419         PetscCall(PetscFVGetNumComponents(fv, &Nc));
420         Nb   = Nc;
421         PetscCall(PetscFVGetCellTabulation(fv, &prob->T[f]));
422         /* TODO: should PetscFV also have face tabulation? Otherwise there will be a null pointer in prob->basisFace */
423       } else SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
424     }
425     prob->Nc[f]       = Nc;
426     prob->Nb[f]       = Nb;
427     prob->off[f+1]    = Nc     + prob->off[f];
428     prob->offDer[f+1] = Nc*dim + prob->offDer[f];
429     prob->offCohesive[0][f+1]    = (prob->cohesive[f] ? Nc : Nc*2)          + prob->offCohesive[0][f];
430     prob->offDerCohesive[0][f+1] = (prob->cohesive[f] ? Nc : Nc*2)*dimEmbed + prob->offDerCohesive[0][f];
431     prob->offCohesive[1][f]      = (prob->cohesive[f] ? 0 : Nc)             + prob->offCohesive[0][f];
432     prob->offDerCohesive[1][f]   = (prob->cohesive[f] ? 0 : Nc)*dimEmbed    + prob->offDerCohesive[0][f];
433     prob->offCohesive[2][f+1]    = (prob->cohesive[f] ? Nc : Nc*2)          + prob->offCohesive[2][f];
434     prob->offDerCohesive[2][f+1] = (prob->cohesive[f] ? Nc : Nc*2)*dimEmbed + prob->offDerCohesive[2][f];
435     if (q) PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL));
436     NqMax          = PetscMax(NqMax, Nq);
437     NbMax          = PetscMax(NbMax, Nb);
438     NcMax          = PetscMax(NcMax, Nc);
439     prob->totDim  += Nb;
440     prob->totComp += Nc;
441     /* There are two faces for all fields on a cohesive cell, except for cohesive fields */
442     if (prob->isCohesive && !prob->cohesive[f]) prob->totDim += Nb;
443   }
444   prob->offCohesive[1][Nf]    = prob->offCohesive[0][Nf];
445   prob->offDerCohesive[1][Nf] = prob->offDerCohesive[0][Nf];
446   /* Allocate works space */
447   NsMax = 2; /* A non-cohesive discretizations can be used on a cohesive cell, so we need this extra workspace for all DS */
448   PetscCall(PetscMalloc3(NsMax*prob->totComp,&prob->u,NsMax*prob->totComp,&prob->u_t,NsMax*prob->totComp*dimEmbed + (hasH ? NsMax*prob->totComp*dimEmbed*dimEmbed : 0),&prob->u_x));
449   PetscCall(PetscMalloc5(dimEmbed,&prob->x,NbMax*NcMax,&prob->basisReal,NbMax*NcMax*dimEmbed,&prob->basisDerReal,NbMax*NcMax,&prob->testReal,NbMax*NcMax*dimEmbed,&prob->testDerReal));
450   ierr = PetscMalloc6(NsMax*NqMax*NcMax,&prob->f0,NsMax*NqMax*NcMax*dimEmbed,&prob->f1,
451                       NsMax*NsMax*NqMax*NcMax*NcMax,&prob->g0,NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed,&prob->g1,
452                       NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed,&prob->g2,NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed*dimEmbed,&prob->g3);PetscCall(ierr);
453   if (prob->ops->setup) PetscCall((*prob->ops->setup)(prob));
454   prob->setup = PETSC_TRUE;
455   PetscFunctionReturn(0);
456 }
457 
458 static PetscErrorCode PetscDSDestroyStructs_Static(PetscDS prob)
459 {
460   PetscFunctionBegin;
461   PetscCall(PetscFree2(prob->Nc,prob->Nb));
462   PetscCall(PetscFree2(prob->off,prob->offDer));
463   PetscCall(PetscFree6(prob->offCohesive[0],prob->offCohesive[1],prob->offCohesive[2],prob->offDerCohesive[0],prob->offDerCohesive[1],prob->offDerCohesive[2]));
464   PetscCall(PetscFree2(prob->T,prob->Tf));
465   PetscCall(PetscFree3(prob->u,prob->u_t,prob->u_x));
466   PetscCall(PetscFree5(prob->x,prob->basisReal, prob->basisDerReal,prob->testReal,prob->testDerReal));
467   PetscCall(PetscFree6(prob->f0,prob->f1,prob->g0,prob->g1,prob->g2,prob->g3));
468   PetscFunctionReturn(0);
469 }
470 
471 static PetscErrorCode PetscDSEnlarge_Static(PetscDS prob, PetscInt NfNew)
472 {
473   PetscObject      *tmpd;
474   PetscBool        *tmpi;
475   PetscInt         *tmpk;
476   PetscBool        *tmpc;
477   PetscPointFunc   *tmpup;
478   PetscSimplePointFunc *tmpexactSol,  *tmpexactSol_t;
479   void                **tmpexactCtx, **tmpexactCtx_t;
480   void            **tmpctx;
481   PetscInt          Nf = prob->Nf, f;
482 
483   PetscFunctionBegin;
484   if (Nf >= NfNew) PetscFunctionReturn(0);
485   prob->setup = PETSC_FALSE;
486   PetscCall(PetscDSDestroyStructs_Static(prob));
487   PetscCall(PetscMalloc4(NfNew, &tmpd, NfNew, &tmpi, NfNew, &tmpc, NfNew, &tmpk));
488   for (f = 0; f < Nf; ++f) {tmpd[f] = prob->disc[f]; tmpi[f] = prob->implicit[f]; tmpc[f] = prob->cohesive[f]; tmpk[f] = prob->jetDegree[f];}
489   for (f = Nf; f < NfNew; ++f) {tmpd[f] = NULL; tmpi[f] = PETSC_TRUE, tmpc[f] = PETSC_FALSE; tmpk[f] = 1;}
490   PetscCall(PetscFree4(prob->disc, prob->implicit, prob->cohesive, prob->jetDegree));
491   PetscCall(PetscWeakFormSetNumFields(prob->wf, NfNew));
492   prob->Nf        = NfNew;
493   prob->disc      = tmpd;
494   prob->implicit  = tmpi;
495   prob->cohesive  = tmpc;
496   prob->jetDegree = tmpk;
497   PetscCall(PetscCalloc2(NfNew, &tmpup, NfNew, &tmpctx));
498   for (f = 0; f < Nf; ++f) tmpup[f] = prob->update[f];
499   for (f = 0; f < Nf; ++f) tmpctx[f] = prob->ctx[f];
500   for (f = Nf; f < NfNew; ++f) tmpup[f] = NULL;
501   for (f = Nf; f < NfNew; ++f) tmpctx[f] = NULL;
502   PetscCall(PetscFree2(prob->update, prob->ctx));
503   prob->update = tmpup;
504   prob->ctx = tmpctx;
505   PetscCall(PetscCalloc4(NfNew, &tmpexactSol, NfNew, &tmpexactCtx, NfNew, &tmpexactSol_t, NfNew, &tmpexactCtx_t));
506   for (f = 0; f < Nf; ++f) tmpexactSol[f] = prob->exactSol[f];
507   for (f = 0; f < Nf; ++f) tmpexactCtx[f] = prob->exactCtx[f];
508   for (f = 0; f < Nf; ++f) tmpexactSol_t[f] = prob->exactSol_t[f];
509   for (f = 0; f < Nf; ++f) tmpexactCtx_t[f] = prob->exactCtx_t[f];
510   for (f = Nf; f < NfNew; ++f) tmpexactSol[f] = NULL;
511   for (f = Nf; f < NfNew; ++f) tmpexactCtx[f] = NULL;
512   for (f = Nf; f < NfNew; ++f) tmpexactSol_t[f] = NULL;
513   for (f = Nf; f < NfNew; ++f) tmpexactCtx_t[f] = NULL;
514   PetscCall(PetscFree4(prob->exactSol, prob->exactCtx, prob->exactSol_t, prob->exactCtx_t));
515   prob->exactSol = tmpexactSol;
516   prob->exactCtx = tmpexactCtx;
517   prob->exactSol_t = tmpexactSol_t;
518   prob->exactCtx_t = tmpexactCtx_t;
519   PetscFunctionReturn(0);
520 }
521 
522 /*@
523   PetscDSDestroy - Destroys a PetscDS object
524 
525   Collective on prob
526 
527   Input Parameter:
528 . prob - the PetscDS object to destroy
529 
530   Level: developer
531 
532 .seealso PetscDSView()
533 @*/
534 PetscErrorCode PetscDSDestroy(PetscDS *ds)
535 {
536   PetscInt       f;
537 
538   PetscFunctionBegin;
539   if (!*ds) PetscFunctionReturn(0);
540   PetscValidHeaderSpecific((*ds), PETSCDS_CLASSID, 1);
541 
542   if (--((PetscObject)(*ds))->refct > 0) {*ds = NULL; PetscFunctionReturn(0);}
543   ((PetscObject) (*ds))->refct = 0;
544   if ((*ds)->subprobs) {
545     PetscInt dim, d;
546 
547     PetscCall(PetscDSGetSpatialDimension(*ds, &dim));
548     for (d = 0; d < dim; ++d) PetscCall(PetscDSDestroy(&(*ds)->subprobs[d]));
549   }
550   PetscCall(PetscFree((*ds)->subprobs));
551   PetscCall(PetscDSDestroyStructs_Static(*ds));
552   for (f = 0; f < (*ds)->Nf; ++f) {
553     PetscCall(PetscObjectDereference((*ds)->disc[f]));
554   }
555   PetscCall(PetscFree4((*ds)->disc, (*ds)->implicit, (*ds)->cohesive, (*ds)->jetDegree));
556   PetscCall(PetscWeakFormDestroy(&(*ds)->wf));
557   PetscCall(PetscFree2((*ds)->update,(*ds)->ctx));
558   PetscCall(PetscFree4((*ds)->exactSol,(*ds)->exactCtx,(*ds)->exactSol_t,(*ds)->exactCtx_t));
559   if ((*ds)->ops->destroy) PetscCall((*(*ds)->ops->destroy)(*ds));
560   PetscCall(PetscDSDestroyBoundary(*ds));
561   PetscCall(PetscFree((*ds)->constants));
562   PetscCall(PetscHeaderDestroy(ds));
563   PetscFunctionReturn(0);
564 }
565 
566 /*@
567   PetscDSCreate - Creates an empty PetscDS object. The type can then be set with PetscDSSetType().
568 
569   Collective
570 
571   Input Parameter:
572 . comm - The communicator for the PetscDS object
573 
574   Output Parameter:
575 . ds   - The PetscDS object
576 
577   Level: beginner
578 
579 .seealso: PetscDSSetType(), PETSCDSBASIC
580 @*/
581 PetscErrorCode PetscDSCreate(MPI_Comm comm, PetscDS *ds)
582 {
583   PetscDS        p;
584 
585   PetscFunctionBegin;
586   PetscValidPointer(ds, 2);
587   *ds  = NULL;
588   PetscCall(PetscDSInitializePackage());
589 
590   PetscCall(PetscHeaderCreate(p, PETSCDS_CLASSID, "PetscDS", "Discrete System", "PetscDS", comm, PetscDSDestroy, PetscDSView));
591 
592   p->Nf           = 0;
593   p->setup        = PETSC_FALSE;
594   p->numConstants = 0;
595   p->constants    = NULL;
596   p->dimEmbed     = -1;
597   p->useJacPre    = PETSC_TRUE;
598   PetscCall(PetscWeakFormCreate(comm, &p->wf));
599 
600   *ds = p;
601   PetscFunctionReturn(0);
602 }
603 
604 /*@
605   PetscDSGetNumFields - Returns the number of fields in the DS
606 
607   Not collective
608 
609   Input Parameter:
610 . prob - The PetscDS object
611 
612   Output Parameter:
613 . Nf - The number of fields
614 
615   Level: beginner
616 
617 .seealso: PetscDSGetSpatialDimension(), PetscDSCreate()
618 @*/
619 PetscErrorCode PetscDSGetNumFields(PetscDS prob, PetscInt *Nf)
620 {
621   PetscFunctionBegin;
622   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
623   PetscValidIntPointer(Nf, 2);
624   *Nf = prob->Nf;
625   PetscFunctionReturn(0);
626 }
627 
628 /*@
629   PetscDSGetSpatialDimension - Returns the spatial dimension of the DS, meaning the topological dimension of the discretizations
630 
631   Not collective
632 
633   Input Parameter:
634 . prob - The PetscDS object
635 
636   Output Parameter:
637 . dim - The spatial dimension
638 
639   Level: beginner
640 
641 .seealso: PetscDSGetCoordinateDimension(), PetscDSGetNumFields(), PetscDSCreate()
642 @*/
643 PetscErrorCode PetscDSGetSpatialDimension(PetscDS prob, PetscInt *dim)
644 {
645   PetscFunctionBegin;
646   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
647   PetscValidIntPointer(dim, 2);
648   *dim = 0;
649   if (prob->Nf) {
650     PetscObject  obj;
651     PetscClassId id;
652 
653     PetscCall(PetscDSGetDiscretization(prob, 0, &obj));
654     if (obj) {
655       PetscCall(PetscObjectGetClassId(obj, &id));
656       if (id == PETSCFE_CLASSID)      PetscCall(PetscFEGetSpatialDimension((PetscFE) obj, dim));
657       else if (id == PETSCFV_CLASSID) PetscCall(PetscFVGetSpatialDimension((PetscFV) obj, dim));
658       else SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", 0);
659     }
660   }
661   PetscFunctionReturn(0);
662 }
663 
664 /*@
665   PetscDSGetCoordinateDimension - Returns the coordinate dimension of the DS, meaning the dimension of the space into which the discretiaztions are embedded
666 
667   Not collective
668 
669   Input Parameter:
670 . prob - The PetscDS object
671 
672   Output Parameter:
673 . dimEmbed - The coordinate dimension
674 
675   Level: beginner
676 
677 .seealso: PetscDSSetCoordinateDimension(), PetscDSGetSpatialDimension(), PetscDSGetNumFields(), PetscDSCreate()
678 @*/
679 PetscErrorCode PetscDSGetCoordinateDimension(PetscDS prob, PetscInt *dimEmbed)
680 {
681   PetscFunctionBegin;
682   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
683   PetscValidIntPointer(dimEmbed, 2);
684   PetscCheckFalse(prob->dimEmbed < 0,PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONGSTATE, "No coordinate dimension set for this DS");
685   *dimEmbed = prob->dimEmbed;
686   PetscFunctionReturn(0);
687 }
688 
689 /*@
690   PetscDSSetCoordinateDimension - Set the coordinate dimension of the DS, meaning the dimension of the space into which the discretiaztions are embedded
691 
692   Logically collective on prob
693 
694   Input Parameters:
695 + prob - The PetscDS object
696 - dimEmbed - The coordinate dimension
697 
698   Level: beginner
699 
700 .seealso: PetscDSGetCoordinateDimension(), PetscDSGetSpatialDimension(), PetscDSGetNumFields(), PetscDSCreate()
701 @*/
702 PetscErrorCode PetscDSSetCoordinateDimension(PetscDS prob, PetscInt dimEmbed)
703 {
704   PetscFunctionBegin;
705   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
706   PetscCheckFalse(dimEmbed < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate dimension must be non-negative, not %D", dimEmbed);
707   prob->dimEmbed = dimEmbed;
708   PetscFunctionReturn(0);
709 }
710 
711 /*@
712   PetscDSIsCohesive - Returns the flag indicating that this DS is for a cohesive cell
713 
714   Not collective
715 
716   Input Parameter:
717 . ds - The PetscDS object
718 
719   Output Parameter:
720 . isCohesive - The flag
721 
722   Level: developer
723 
724 .seealso: PetscDSGetNumCohesive(), PetscDSGetCohesive(), PetscDSSetCohesive(), PetscDSCreate()
725 @*/
726 PetscErrorCode PetscDSIsCohesive(PetscDS ds, PetscBool *isCohesive)
727 {
728   PetscFunctionBegin;
729   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
730   PetscValidBoolPointer(isCohesive, 2);
731   *isCohesive = ds->isCohesive;
732   PetscFunctionReturn(0);
733 }
734 
735 /*@
736   PetscDSGetNumCohesive - Returns the numer of cohesive fields, meaning those defined on the interior of a cohesive cell
737 
738   Not collective
739 
740   Input Parameter:
741 . ds - The PetscDS object
742 
743   Output Parameter:
744 . numCohesive - The number of cohesive fields
745 
746   Level: developer
747 
748 .seealso: PetscDSSetCohesive(), PetscDSCreate()
749 @*/
750 PetscErrorCode PetscDSGetNumCohesive(PetscDS ds, PetscInt *numCohesive)
751 {
752   PetscInt f;
753 
754   PetscFunctionBegin;
755   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
756   PetscValidIntPointer(numCohesive, 2);
757   *numCohesive = 0;
758   for (f = 0;  f < ds->Nf; ++f) *numCohesive += ds->cohesive[f] ? 1 : 0;
759   PetscFunctionReturn(0);
760 }
761 
762 /*@
763   PetscDSGetCohesive - Returns the flag indicating that a field is cohesive, meaning it is defined on the interior of a cohesive cell
764 
765   Not collective
766 
767   Input Parameters:
768 + ds - The PetscDS object
769 - f  - The field index
770 
771   Output Parameter:
772 . isCohesive - The flag
773 
774   Level: developer
775 
776 .seealso: PetscDSSetCohesive(), PetscDSIsCohesive(), PetscDSCreate()
777 @*/
778 PetscErrorCode PetscDSGetCohesive(PetscDS ds, PetscInt f, PetscBool *isCohesive)
779 {
780   PetscFunctionBegin;
781   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
782   PetscValidBoolPointer(isCohesive, 3);
783   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
784   *isCohesive = ds->cohesive[f];
785   PetscFunctionReturn(0);
786 }
787 
788 /*@
789   PetscDSSetCohesive - Set the flag indicating that a field is cohesive, meaning it is defined on the interior of a cohesive cell
790 
791   Not collective
792 
793   Input Parameters:
794 + ds - The PetscDS object
795 . f  - The field index
796 - isCohesive - The flag for a cohesive field
797 
798   Level: developer
799 
800 .seealso: PetscDSGetCohesive(), PetscDSIsCohesive(), PetscDSCreate()
801 @*/
802 PetscErrorCode PetscDSSetCohesive(PetscDS ds, PetscInt f, PetscBool isCohesive)
803 {
804   PetscInt i;
805 
806   PetscFunctionBegin;
807   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
808   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
809   ds->cohesive[f] = isCohesive;
810   ds->isCohesive = PETSC_FALSE;
811   for (i = 0; i < ds->Nf; ++i) ds->isCohesive = ds->isCohesive || ds->cohesive[f] ? PETSC_TRUE : PETSC_FALSE;
812   PetscFunctionReturn(0);
813 }
814 
815 /*@
816   PetscDSGetTotalDimension - Returns the total size of the approximation space for this system
817 
818   Not collective
819 
820   Input Parameter:
821 . prob - The PetscDS object
822 
823   Output Parameter:
824 . dim - The total problem dimension
825 
826   Level: beginner
827 
828 .seealso: PetscDSGetNumFields(), PetscDSCreate()
829 @*/
830 PetscErrorCode PetscDSGetTotalDimension(PetscDS prob, PetscInt *dim)
831 {
832   PetscFunctionBegin;
833   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
834   PetscCall(PetscDSSetUp(prob));
835   PetscValidIntPointer(dim, 2);
836   *dim = prob->totDim;
837   PetscFunctionReturn(0);
838 }
839 
840 /*@
841   PetscDSGetTotalComponents - Returns the total number of components in this system
842 
843   Not collective
844 
845   Input Parameter:
846 . prob - The PetscDS object
847 
848   Output Parameter:
849 . dim - The total number of components
850 
851   Level: beginner
852 
853 .seealso: PetscDSGetNumFields(), PetscDSCreate()
854 @*/
855 PetscErrorCode PetscDSGetTotalComponents(PetscDS prob, PetscInt *Nc)
856 {
857   PetscFunctionBegin;
858   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
859   PetscCall(PetscDSSetUp(prob));
860   PetscValidIntPointer(Nc, 2);
861   *Nc = prob->totComp;
862   PetscFunctionReturn(0);
863 }
864 
865 /*@
866   PetscDSGetDiscretization - Returns the discretization object for the given field
867 
868   Not collective
869 
870   Input Parameters:
871 + prob - The PetscDS object
872 - f - The field number
873 
874   Output Parameter:
875 . disc - The discretization object
876 
877   Level: beginner
878 
879 .seealso: PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
880 @*/
881 PetscErrorCode PetscDSGetDiscretization(PetscDS prob, PetscInt f, PetscObject *disc)
882 {
883   PetscFunctionBeginHot;
884   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
885   PetscValidPointer(disc, 3);
886   PetscCheckFalse((f < 0) || (f >= prob->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
887   *disc = prob->disc[f];
888   PetscFunctionReturn(0);
889 }
890 
891 /*@
892   PetscDSSetDiscretization - Sets the discretization object for the given field
893 
894   Not collective
895 
896   Input Parameters:
897 + prob - The PetscDS object
898 . f - The field number
899 - disc - The discretization object
900 
901   Level: beginner
902 
903 .seealso: PetscDSGetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
904 @*/
905 PetscErrorCode PetscDSSetDiscretization(PetscDS prob, PetscInt f, PetscObject disc)
906 {
907   PetscFunctionBegin;
908   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
909   if (disc) PetscValidPointer(disc, 3);
910   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
911   PetscCall(PetscDSEnlarge_Static(prob, f+1));
912   PetscCall(PetscObjectDereference(prob->disc[f]));
913   prob->disc[f] = disc;
914   PetscCall(PetscObjectReference(disc));
915   if (disc) {
916     PetscClassId id;
917 
918     PetscCall(PetscObjectGetClassId(disc, &id));
919     if (id == PETSCFE_CLASSID) {
920       PetscCall(PetscDSSetImplicit(prob, f, PETSC_TRUE));
921     } else if (id == PETSCFV_CLASSID) {
922       PetscCall(PetscDSSetImplicit(prob, f, PETSC_FALSE));
923     }
924     PetscCall(PetscDSSetJetDegree(prob, f, 1));
925   }
926   PetscFunctionReturn(0);
927 }
928 
929 /*@
930   PetscDSGetWeakForm - Returns the weak form object
931 
932   Not collective
933 
934   Input Parameter:
935 . ds - The PetscDS object
936 
937   Output Parameter:
938 . wf - The weak form object
939 
940   Level: beginner
941 
942 .seealso: PetscDSSetWeakForm(), PetscDSGetNumFields(), PetscDSCreate()
943 @*/
944 PetscErrorCode PetscDSGetWeakForm(PetscDS ds, PetscWeakForm *wf)
945 {
946   PetscFunctionBegin;
947   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
948   PetscValidPointer(wf, 2);
949   *wf = ds->wf;
950   PetscFunctionReturn(0);
951 }
952 
953 /*@
954   PetscDSSetWeakForm - Sets the weak form object
955 
956   Not collective
957 
958   Input Parameters:
959 + ds - The PetscDS object
960 - wf - The weak form object
961 
962   Level: beginner
963 
964 .seealso: PetscDSGetWeakForm(), PetscDSGetNumFields(), PetscDSCreate()
965 @*/
966 PetscErrorCode PetscDSSetWeakForm(PetscDS ds, PetscWeakForm wf)
967 {
968   PetscFunctionBegin;
969   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
970   PetscValidHeaderSpecific(wf, PETSCWEAKFORM_CLASSID, 2);
971   PetscCall(PetscObjectDereference((PetscObject) ds->wf));
972   ds->wf = wf;
973   PetscCall(PetscObjectReference((PetscObject) wf));
974   PetscCall(PetscWeakFormSetNumFields(wf, ds->Nf));
975   PetscFunctionReturn(0);
976 }
977 
978 /*@
979   PetscDSAddDiscretization - Adds a discretization object
980 
981   Not collective
982 
983   Input Parameters:
984 + prob - The PetscDS object
985 - disc - The boundary discretization object
986 
987   Level: beginner
988 
989 .seealso: PetscDSGetDiscretization(), PetscDSSetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
990 @*/
991 PetscErrorCode PetscDSAddDiscretization(PetscDS prob, PetscObject disc)
992 {
993   PetscFunctionBegin;
994   PetscCall(PetscDSSetDiscretization(prob, prob->Nf, disc));
995   PetscFunctionReturn(0);
996 }
997 
998 /*@
999   PetscDSGetQuadrature - Returns the quadrature, which must agree for all fields in the DS
1000 
1001   Not collective
1002 
1003   Input Parameter:
1004 . prob - The PetscDS object
1005 
1006   Output Parameter:
1007 . q - The quadrature object
1008 
1009 Level: intermediate
1010 
1011 .seealso: PetscDSSetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
1012 @*/
1013 PetscErrorCode PetscDSGetQuadrature(PetscDS prob, PetscQuadrature *q)
1014 {
1015   PetscObject    obj;
1016   PetscClassId   id;
1017 
1018   PetscFunctionBegin;
1019   *q = NULL;
1020   if (!prob->Nf) PetscFunctionReturn(0);
1021   PetscCall(PetscDSGetDiscretization(prob, 0, &obj));
1022   PetscCall(PetscObjectGetClassId(obj, &id));
1023   if      (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE) obj, q));
1024   else if (id == PETSCFV_CLASSID) PetscCall(PetscFVGetQuadrature((PetscFV) obj, q));
1025   else SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", 0);
1026   PetscFunctionReturn(0);
1027 }
1028 
1029 /*@
1030   PetscDSGetImplicit - Returns the flag for implicit solve for this field. This is just a guide for IMEX
1031 
1032   Not collective
1033 
1034   Input Parameters:
1035 + prob - The PetscDS object
1036 - f - The field number
1037 
1038   Output Parameter:
1039 . implicit - The flag indicating what kind of solve to use for this field
1040 
1041   Level: developer
1042 
1043 .seealso: PetscDSSetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
1044 @*/
1045 PetscErrorCode PetscDSGetImplicit(PetscDS prob, PetscInt f, PetscBool *implicit)
1046 {
1047   PetscFunctionBegin;
1048   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1049   PetscValidBoolPointer(implicit, 3);
1050   PetscCheckFalse((f < 0) || (f >= prob->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
1051   *implicit = prob->implicit[f];
1052   PetscFunctionReturn(0);
1053 }
1054 
1055 /*@
1056   PetscDSSetImplicit - Set the flag for implicit solve for this field. This is just a guide for IMEX
1057 
1058   Not collective
1059 
1060   Input Parameters:
1061 + prob - The PetscDS object
1062 . f - The field number
1063 - implicit - The flag indicating what kind of solve to use for this field
1064 
1065   Level: developer
1066 
1067 .seealso: PetscDSGetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
1068 @*/
1069 PetscErrorCode PetscDSSetImplicit(PetscDS prob, PetscInt f, PetscBool implicit)
1070 {
1071   PetscFunctionBegin;
1072   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1073   PetscCheckFalse((f < 0) || (f >= prob->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
1074   prob->implicit[f] = implicit;
1075   PetscFunctionReturn(0);
1076 }
1077 
1078 /*@
1079   PetscDSGetJetDegree - Returns the highest derivative for this field equation, or the k-jet that the discretization needs to tabulate.
1080 
1081   Not collective
1082 
1083   Input Parameters:
1084 + ds - The PetscDS object
1085 - f  - The field number
1086 
1087   Output Parameter:
1088 . k  - The highest derivative we need to tabulate
1089 
1090   Level: developer
1091 
1092 .seealso: PetscDSSetJetDegree(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
1093 @*/
1094 PetscErrorCode PetscDSGetJetDegree(PetscDS ds, PetscInt f, PetscInt *k)
1095 {
1096   PetscFunctionBegin;
1097   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1098   PetscValidIntPointer(k, 3);
1099   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
1100   *k = ds->jetDegree[f];
1101   PetscFunctionReturn(0);
1102 }
1103 
1104 /*@
1105   PetscDSSetJetDegree - Set the highest derivative for this field equation, or the k-jet that the discretization needs to tabulate.
1106 
1107   Not collective
1108 
1109   Input Parameters:
1110 + ds - The PetscDS object
1111 . f  - The field number
1112 - k  - The highest derivative we need to tabulate
1113 
1114   Level: developer
1115 
1116 .seealso: PetscDSGetJetDegree(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
1117 @*/
1118 PetscErrorCode PetscDSSetJetDegree(PetscDS ds, PetscInt f, PetscInt k)
1119 {
1120   PetscFunctionBegin;
1121   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1122   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
1123   ds->jetDegree[f] = k;
1124   PetscFunctionReturn(0);
1125 }
1126 
1127 PetscErrorCode PetscDSGetObjective(PetscDS ds, PetscInt f,
1128                                    void (**obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1129                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1130                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1131                                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
1132 {
1133   PetscPointFunc *tmp;
1134   PetscInt        n;
1135 
1136   PetscFunctionBegin;
1137   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1138   PetscValidPointer(obj, 3);
1139   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
1140   PetscCall(PetscWeakFormGetObjective(ds->wf, NULL, 0, f, 0, &n, &tmp));
1141   *obj = tmp ? tmp[0] : NULL;
1142   PetscFunctionReturn(0);
1143 }
1144 
1145 PetscErrorCode PetscDSSetObjective(PetscDS ds, PetscInt f,
1146                                    void (*obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1147                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1148                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1149                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
1150 {
1151   PetscFunctionBegin;
1152   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1153   if (obj) PetscValidFunction(obj, 3);
1154   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1155   PetscCall(PetscWeakFormSetIndexObjective(ds->wf, NULL, 0, f, 0, 0, obj));
1156   PetscFunctionReturn(0);
1157 }
1158 
1159 /*@C
1160   PetscDSGetResidual - Get the pointwise residual function for a given test field
1161 
1162   Not collective
1163 
1164   Input Parameters:
1165 + ds - The PetscDS
1166 - f  - The test field number
1167 
1168   Output Parameters:
1169 + f0 - integrand for the test function term
1170 - f1 - integrand for the test function gradient term
1171 
1172   Note: We are using a first order FEM model for the weak form:
1173 
1174   \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)
1175 
1176 The calling sequence for the callbacks f0 and f1 is given by:
1177 
1178 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1179 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1180 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1181 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
1182 
1183 + dim - the spatial dimension
1184 . Nf - the number of fields
1185 . uOff - the offset into u[] and u_t[] for each field
1186 . uOff_x - the offset into u_x[] for each field
1187 . u - each field evaluated at the current point
1188 . u_t - the time derivative of each field evaluated at the current point
1189 . u_x - the gradient of each field evaluated at the current point
1190 . aOff - the offset into a[] and a_t[] for each auxiliary field
1191 . aOff_x - the offset into a_x[] for each auxiliary field
1192 . a - each auxiliary field evaluated at the current point
1193 . a_t - the time derivative of each auxiliary field evaluated at the current point
1194 . a_x - the gradient of auxiliary each field evaluated at the current point
1195 . t - current time
1196 . x - coordinates of the current point
1197 . numConstants - number of constant parameters
1198 . constants - constant parameters
1199 - f0 - output values at the current point
1200 
1201   Level: intermediate
1202 
1203 .seealso: PetscDSSetResidual()
1204 @*/
1205 PetscErrorCode PetscDSGetResidual(PetscDS ds, PetscInt f,
1206                                   void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1207                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1208                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1209                                               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1210                                   void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1211                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1212                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1213                                               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1214 {
1215   PetscPointFunc *tmp0, *tmp1;
1216   PetscInt        n0, n1;
1217 
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1220   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
1221   PetscCall(PetscWeakFormGetResidual(ds->wf, NULL, 0, f, 0, &n0, &tmp0, &n1, &tmp1));
1222   *f0  = tmp0 ? tmp0[0] : NULL;
1223   *f1  = tmp1 ? tmp1[0] : NULL;
1224   PetscFunctionReturn(0);
1225 }
1226 
1227 /*@C
1228   PetscDSSetResidual - Set the pointwise residual function for a given test field
1229 
1230   Not collective
1231 
1232   Input Parameters:
1233 + ds - The PetscDS
1234 . f  - The test field number
1235 . f0 - integrand for the test function term
1236 - f1 - integrand for the test function gradient term
1237 
1238   Note: We are using a first order FEM model for the weak form:
1239 
1240   \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)
1241 
1242 The calling sequence for the callbacks f0 and f1 is given by:
1243 
1244 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1245 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1246 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1247 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
1248 
1249 + dim - the spatial dimension
1250 . Nf - the number of fields
1251 . uOff - the offset into u[] and u_t[] for each field
1252 . uOff_x - the offset into u_x[] for each field
1253 . u - each field evaluated at the current point
1254 . u_t - the time derivative of each field evaluated at the current point
1255 . u_x - the gradient of each field evaluated at the current point
1256 . aOff - the offset into a[] and a_t[] for each auxiliary field
1257 . aOff_x - the offset into a_x[] for each auxiliary field
1258 . a - each auxiliary field evaluated at the current point
1259 . a_t - the time derivative of each auxiliary field evaluated at the current point
1260 . a_x - the gradient of auxiliary each field evaluated at the current point
1261 . t - current time
1262 . x - coordinates of the current point
1263 . numConstants - number of constant parameters
1264 . constants - constant parameters
1265 - f0 - output values at the current point
1266 
1267   Level: intermediate
1268 
1269 .seealso: PetscDSGetResidual()
1270 @*/
1271 PetscErrorCode PetscDSSetResidual(PetscDS ds, PetscInt f,
1272                                   void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1273                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1274                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1275                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1276                                   void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1277                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1278                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1279                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1280 {
1281   PetscFunctionBegin;
1282   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1283   if (f0) PetscValidFunction(f0, 3);
1284   if (f1) PetscValidFunction(f1, 4);
1285   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1286   PetscCall(PetscWeakFormSetIndexResidual(ds->wf, NULL, 0, f, 0, 0, f0, 0, f1));
1287   PetscFunctionReturn(0);
1288 }
1289 
1290 /*@C
1291   PetscDSGetRHSResidual - Get the pointwise RHS residual function for explicit timestepping for a given test field
1292 
1293   Not collective
1294 
1295   Input Parameters:
1296 + ds - The PetscDS
1297 - f  - The test field number
1298 
1299   Output Parameters:
1300 + f0 - integrand for the test function term
1301 - f1 - integrand for the test function gradient term
1302 
1303   Note: We are using a first order FEM model for the weak form:
1304 
1305   \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)
1306 
1307 The calling sequence for the callbacks f0 and f1 is given by:
1308 
1309 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1310 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1311 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1312 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
1313 
1314 + dim - the spatial dimension
1315 . Nf - the number of fields
1316 . uOff - the offset into u[] and u_t[] for each field
1317 . uOff_x - the offset into u_x[] for each field
1318 . u - each field evaluated at the current point
1319 . u_t - the time derivative of each field evaluated at the current point
1320 . u_x - the gradient of each field evaluated at the current point
1321 . aOff - the offset into a[] and a_t[] for each auxiliary field
1322 . aOff_x - the offset into a_x[] for each auxiliary field
1323 . a - each auxiliary field evaluated at the current point
1324 . a_t - the time derivative of each auxiliary field evaluated at the current point
1325 . a_x - the gradient of auxiliary each field evaluated at the current point
1326 . t - current time
1327 . x - coordinates of the current point
1328 . numConstants - number of constant parameters
1329 . constants - constant parameters
1330 - f0 - output values at the current point
1331 
1332   Level: intermediate
1333 
1334 .seealso: PetscDSSetRHSResidual()
1335 @*/
1336 PetscErrorCode PetscDSGetRHSResidual(PetscDS ds, PetscInt f,
1337                                      void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1338                                                  const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1339                                                  const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1340                                                  PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1341                                      void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1342                                                  const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1343                                                  const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1344                                                  PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1345 {
1346   PetscPointFunc *tmp0, *tmp1;
1347   PetscInt        n0, n1;
1348 
1349   PetscFunctionBegin;
1350   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1351   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
1352   PetscCall(PetscWeakFormGetResidual(ds->wf, NULL, 0, f, 100, &n0, &tmp0, &n1, &tmp1));
1353   *f0  = tmp0 ? tmp0[0] : NULL;
1354   *f1  = tmp1 ? tmp1[0] : NULL;
1355   PetscFunctionReturn(0);
1356 }
1357 
1358 /*@C
1359   PetscDSSetRHSResidual - Set the pointwise residual function for explicit timestepping for a given test field
1360 
1361   Not collective
1362 
1363   Input Parameters:
1364 + ds - The PetscDS
1365 . f  - The test field number
1366 . f0 - integrand for the test function term
1367 - f1 - integrand for the test function gradient term
1368 
1369   Note: We are using a first order FEM model for the weak form:
1370 
1371   \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)
1372 
1373 The calling sequence for the callbacks f0 and f1 is given by:
1374 
1375 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1376 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1377 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1378 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
1379 
1380 + dim - the spatial dimension
1381 . Nf - the number of fields
1382 . uOff - the offset into u[] and u_t[] for each field
1383 . uOff_x - the offset into u_x[] for each field
1384 . u - each field evaluated at the current point
1385 . u_t - the time derivative of each field evaluated at the current point
1386 . u_x - the gradient of each field evaluated at the current point
1387 . aOff - the offset into a[] and a_t[] for each auxiliary field
1388 . aOff_x - the offset into a_x[] for each auxiliary field
1389 . a - each auxiliary field evaluated at the current point
1390 . a_t - the time derivative of each auxiliary field evaluated at the current point
1391 . a_x - the gradient of auxiliary each field evaluated at the current point
1392 . t - current time
1393 . x - coordinates of the current point
1394 . numConstants - number of constant parameters
1395 . constants - constant parameters
1396 - f0 - output values at the current point
1397 
1398   Level: intermediate
1399 
1400 .seealso: PetscDSGetResidual()
1401 @*/
1402 PetscErrorCode PetscDSSetRHSResidual(PetscDS ds, PetscInt f,
1403                                      void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1404                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1405                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1406                                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1407                                      void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1408                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1409                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1410                                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1411 {
1412   PetscFunctionBegin;
1413   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1414   if (f0) PetscValidFunction(f0, 3);
1415   if (f1) PetscValidFunction(f1, 4);
1416   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1417   PetscCall(PetscWeakFormSetIndexResidual(ds->wf, NULL, 0, f, 100, 0, f0, 0, f1));
1418   PetscFunctionReturn(0);
1419 }
1420 
1421 /*@C
1422   PetscDSHasJacobian - Signals that Jacobian functions have been set
1423 
1424   Not collective
1425 
1426   Input Parameter:
1427 . prob - The PetscDS
1428 
1429   Output Parameter:
1430 . hasJac - flag that pointwise function for the Jacobian has been set
1431 
1432   Level: intermediate
1433 
1434 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1435 @*/
1436 PetscErrorCode PetscDSHasJacobian(PetscDS ds, PetscBool *hasJac)
1437 {
1438   PetscFunctionBegin;
1439   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1440   PetscCall(PetscWeakFormHasJacobian(ds->wf, hasJac));
1441   PetscFunctionReturn(0);
1442 }
1443 
1444 /*@C
1445   PetscDSGetJacobian - Get the pointwise Jacobian function for given test and basis field
1446 
1447   Not collective
1448 
1449   Input Parameters:
1450 + ds - The PetscDS
1451 . f  - The test field number
1452 - g  - The field number
1453 
1454   Output Parameters:
1455 + g0 - integrand for the test and basis function term
1456 . g1 - integrand for the test function and basis function gradient term
1457 . g2 - integrand for the test function gradient and basis function term
1458 - g3 - integrand for the test function gradient and basis function gradient term
1459 
1460   Note: We are using a first order FEM model for the weak form:
1461 
1462   \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
1463 
1464 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1465 
1466 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1467 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1468 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1469 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1470 
1471 + dim - the spatial dimension
1472 . Nf - the number of fields
1473 . uOff - the offset into u[] and u_t[] for each field
1474 . uOff_x - the offset into u_x[] for each field
1475 . u - each field evaluated at the current point
1476 . u_t - the time derivative of each field evaluated at the current point
1477 . u_x - the gradient of each field evaluated at the current point
1478 . aOff - the offset into a[] and a_t[] for each auxiliary field
1479 . aOff_x - the offset into a_x[] for each auxiliary field
1480 . a - each auxiliary field evaluated at the current point
1481 . a_t - the time derivative of each auxiliary field evaluated at the current point
1482 . a_x - the gradient of auxiliary each field evaluated at the current point
1483 . t - current time
1484 . u_tShift - the multiplier a for dF/dU_t
1485 . x - coordinates of the current point
1486 . numConstants - number of constant parameters
1487 . constants - constant parameters
1488 - g0 - output values at the current point
1489 
1490   Level: intermediate
1491 
1492 .seealso: PetscDSSetJacobian()
1493 @*/
1494 PetscErrorCode PetscDSGetJacobian(PetscDS ds, PetscInt f, PetscInt g,
1495                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1496                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1497                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1498                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1499                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1500                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1501                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1502                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1503                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1504                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1505                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1506                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1507                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1508                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1509                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1510                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1511 {
1512   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
1513   PetscInt       n0, n1, n2, n3;
1514 
1515   PetscFunctionBegin;
1516   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1517   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
1518   PetscCheckFalse((g < 0) || (g >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
1519   PetscCall(PetscWeakFormGetJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
1520   *g0  = tmp0 ? tmp0[0] : NULL;
1521   *g1  = tmp1 ? tmp1[0] : NULL;
1522   *g2  = tmp2 ? tmp2[0] : NULL;
1523   *g3  = tmp3 ? tmp3[0] : NULL;
1524   PetscFunctionReturn(0);
1525 }
1526 
1527 /*@C
1528   PetscDSSetJacobian - Set the pointwise Jacobian function for given test and basis fields
1529 
1530   Not collective
1531 
1532   Input Parameters:
1533 + ds - The PetscDS
1534 . f  - The test field number
1535 . g  - The field number
1536 . g0 - integrand for the test and basis function term
1537 . g1 - integrand for the test function and basis function gradient term
1538 . g2 - integrand for the test function gradient and basis function term
1539 - g3 - integrand for the test function gradient and basis function gradient term
1540 
1541   Note: We are using a first order FEM model for the weak form:
1542 
1543   \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
1544 
1545 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1546 
1547 $ g0(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, const PetscReal x[], PetscScalar g0[])
1551 
1552 + dim - the spatial dimension
1553 . Nf - the number of fields
1554 . uOff - the offset into u[] and u_t[] for each field
1555 . uOff_x - the offset into u_x[] for each field
1556 . u - each field evaluated at the current point
1557 . u_t - the time derivative of each field evaluated at the current point
1558 . u_x - the gradient of each field evaluated at the current point
1559 . aOff - the offset into a[] and a_t[] for each auxiliary field
1560 . aOff_x - the offset into a_x[] for each auxiliary field
1561 . a - each auxiliary field evaluated at the current point
1562 . a_t - the time derivative of each auxiliary field evaluated at the current point
1563 . a_x - the gradient of auxiliary each field evaluated at the current point
1564 . t - current time
1565 . u_tShift - the multiplier a for dF/dU_t
1566 . x - coordinates of the current point
1567 . numConstants - number of constant parameters
1568 . constants - constant parameters
1569 - g0 - output values at the current point
1570 
1571   Level: intermediate
1572 
1573 .seealso: PetscDSGetJacobian()
1574 @*/
1575 PetscErrorCode PetscDSSetJacobian(PetscDS ds, PetscInt f, PetscInt g,
1576                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1577                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1578                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1579                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1580                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1581                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1582                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1583                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1584                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1585                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1586                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1587                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1588                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1589                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1590                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1591                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1592 {
1593   PetscFunctionBegin;
1594   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1595   if (g0) PetscValidFunction(g0, 4);
1596   if (g1) PetscValidFunction(g1, 5);
1597   if (g2) PetscValidFunction(g2, 6);
1598   if (g3) PetscValidFunction(g3, 7);
1599   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1600   PetscCheckFalse(g < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1601   PetscCall(PetscWeakFormSetIndexJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
1602   PetscFunctionReturn(0);
1603 }
1604 
1605 /*@C
1606   PetscDSUseJacobianPreconditioner - Whether to construct a Jacobian preconditioner
1607 
1608   Not collective
1609 
1610   Input Parameters:
1611 + prob - The PetscDS
1612 - useJacPre - flag that enables construction of a Jacobian preconditioner
1613 
1614   Level: intermediate
1615 
1616 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1617 @*/
1618 PetscErrorCode PetscDSUseJacobianPreconditioner(PetscDS prob, PetscBool useJacPre)
1619 {
1620   PetscFunctionBegin;
1621   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1622   prob->useJacPre = useJacPre;
1623   PetscFunctionReturn(0);
1624 }
1625 
1626 /*@C
1627   PetscDSHasJacobianPreconditioner - Signals that a Jacobian preconditioner matrix has been set
1628 
1629   Not collective
1630 
1631   Input Parameter:
1632 . prob - The PetscDS
1633 
1634   Output Parameter:
1635 . hasJacPre - flag that pointwise function for Jacobian preconditioner matrix has been set
1636 
1637   Level: intermediate
1638 
1639 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1640 @*/
1641 PetscErrorCode PetscDSHasJacobianPreconditioner(PetscDS ds, PetscBool *hasJacPre)
1642 {
1643   PetscFunctionBegin;
1644   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1645   *hasJacPre = PETSC_FALSE;
1646   if (!ds->useJacPre) PetscFunctionReturn(0);
1647   PetscCall(PetscWeakFormHasJacobianPreconditioner(ds->wf, hasJacPre));
1648   PetscFunctionReturn(0);
1649 }
1650 
1651 /*@C
1652   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.
1653 
1654   Not collective
1655 
1656   Input Parameters:
1657 + ds - The PetscDS
1658 . f  - The test field number
1659 - g  - The field number
1660 
1661   Output Parameters:
1662 + g0 - integrand for the test and basis function term
1663 . g1 - integrand for the test function and basis function gradient term
1664 . g2 - integrand for the test function gradient and basis function term
1665 - g3 - integrand for the test function gradient and basis function gradient term
1666 
1667   Note: We are using a first order FEM model for the weak form:
1668 
1669   \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
1670 
1671 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1672 
1673 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1674 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1675 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1676 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1677 
1678 + dim - the spatial dimension
1679 . Nf - the number of fields
1680 . uOff - the offset into u[] and u_t[] for each field
1681 . uOff_x - the offset into u_x[] for each field
1682 . u - each field evaluated at the current point
1683 . u_t - the time derivative of each field evaluated at the current point
1684 . u_x - the gradient of each field evaluated at the current point
1685 . aOff - the offset into a[] and a_t[] for each auxiliary field
1686 . aOff_x - the offset into a_x[] for each auxiliary field
1687 . a - each auxiliary field evaluated at the current point
1688 . a_t - the time derivative of each auxiliary field evaluated at the current point
1689 . a_x - the gradient of auxiliary each field evaluated at the current point
1690 . t - current time
1691 . u_tShift - the multiplier a for dF/dU_t
1692 . x - coordinates of the current point
1693 . numConstants - number of constant parameters
1694 . constants - constant parameters
1695 - g0 - output values at the current point
1696 
1697   Level: intermediate
1698 
1699 .seealso: PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1700 @*/
1701 PetscErrorCode PetscDSGetJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g,
1702                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1703                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1704                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1705                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1706                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1707                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1708                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1709                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1710                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1711                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1712                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1713                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1714                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1715                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1716                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1717                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1718 {
1719   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
1720   PetscInt       n0, n1, n2, n3;
1721 
1722   PetscFunctionBegin;
1723   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1724   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
1725   PetscCheckFalse((g < 0) || (g >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
1726   PetscCall(PetscWeakFormGetJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
1727   *g0  = tmp0 ? tmp0[0] : NULL;
1728   *g1  = tmp1 ? tmp1[0] : NULL;
1729   *g2  = tmp2 ? tmp2[0] : NULL;
1730   *g3  = tmp3 ? tmp3[0] : NULL;
1731   PetscFunctionReturn(0);
1732 }
1733 
1734 /*@C
1735   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.
1736 
1737   Not collective
1738 
1739   Input Parameters:
1740 + ds - The PetscDS
1741 . f  - The test field number
1742 . g  - The field number
1743 . g0 - integrand for the test and basis function term
1744 . g1 - integrand for the test function and basis function gradient term
1745 . g2 - integrand for the test function gradient and basis function term
1746 - g3 - integrand for the test function gradient and basis function gradient term
1747 
1748   Note: We are using a first order FEM model for the weak form:
1749 
1750   \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
1751 
1752 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1753 
1754 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1755 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1756 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1757 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1758 
1759 + dim - the spatial dimension
1760 . Nf - the number of fields
1761 . uOff - the offset into u[] and u_t[] for each field
1762 . uOff_x - the offset into u_x[] for each field
1763 . u - each field evaluated at the current point
1764 . u_t - the time derivative of each field evaluated at the current point
1765 . u_x - the gradient of each field evaluated at the current point
1766 . aOff - the offset into a[] and a_t[] for each auxiliary field
1767 . aOff_x - the offset into a_x[] for each auxiliary field
1768 . a - each auxiliary field evaluated at the current point
1769 . a_t - the time derivative of each auxiliary field evaluated at the current point
1770 . a_x - the gradient of auxiliary each field evaluated at the current point
1771 . t - current time
1772 . u_tShift - the multiplier a for dF/dU_t
1773 . x - coordinates of the current point
1774 . numConstants - number of constant parameters
1775 . constants - constant parameters
1776 - g0 - output values at the current point
1777 
1778   Level: intermediate
1779 
1780 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobian()
1781 @*/
1782 PetscErrorCode PetscDSSetJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g,
1783                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1784                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1785                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1786                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1787                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1788                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1789                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1790                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1791                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1792                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1793                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1794                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1795                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1796                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1797                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1798                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1799 {
1800   PetscFunctionBegin;
1801   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1802   if (g0) PetscValidFunction(g0, 4);
1803   if (g1) PetscValidFunction(g1, 5);
1804   if (g2) PetscValidFunction(g2, 6);
1805   if (g3) PetscValidFunction(g3, 7);
1806   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1807   PetscCheckFalse(g < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1808   PetscCall(PetscWeakFormSetIndexJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
1809   PetscFunctionReturn(0);
1810 }
1811 
1812 /*@C
1813   PetscDSHasDynamicJacobian - Signals that a dynamic Jacobian, dF/du_t, has been set
1814 
1815   Not collective
1816 
1817   Input Parameter:
1818 . ds - The PetscDS
1819 
1820   Output Parameter:
1821 . hasDynJac - flag that pointwise function for dynamic Jacobian has been set
1822 
1823   Level: intermediate
1824 
1825 .seealso: PetscDSGetDynamicJacobian(), PetscDSSetDynamicJacobian(), PetscDSGetJacobian()
1826 @*/
1827 PetscErrorCode PetscDSHasDynamicJacobian(PetscDS ds, PetscBool *hasDynJac)
1828 {
1829   PetscFunctionBegin;
1830   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1831   PetscCall(PetscWeakFormHasDynamicJacobian(ds->wf, hasDynJac));
1832   PetscFunctionReturn(0);
1833 }
1834 
1835 /*@C
1836   PetscDSGetDynamicJacobian - Get the pointwise dynamic Jacobian, dF/du_t, function for given test and basis field
1837 
1838   Not collective
1839 
1840   Input Parameters:
1841 + ds - The PetscDS
1842 . f  - The test field number
1843 - g  - The field number
1844 
1845   Output Parameters:
1846 + g0 - integrand for the test and basis function term
1847 . g1 - integrand for the test function and basis function gradient term
1848 . g2 - integrand for the test function gradient and basis function term
1849 - g3 - integrand for the test function gradient and basis function gradient term
1850 
1851   Note: We are using a first order FEM model for the weak form:
1852 
1853   \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
1854 
1855 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1856 
1857 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1858 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1859 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1860 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1861 
1862 + dim - the spatial dimension
1863 . Nf - the number of fields
1864 . uOff - the offset into u[] and u_t[] for each field
1865 . uOff_x - the offset into u_x[] for each field
1866 . u - each field evaluated at the current point
1867 . u_t - the time derivative of each field evaluated at the current point
1868 . u_x - the gradient of each field evaluated at the current point
1869 . aOff - the offset into a[] and a_t[] for each auxiliary field
1870 . aOff_x - the offset into a_x[] for each auxiliary field
1871 . a - each auxiliary field evaluated at the current point
1872 . a_t - the time derivative of each auxiliary field evaluated at the current point
1873 . a_x - the gradient of auxiliary each field evaluated at the current point
1874 . t - current time
1875 . u_tShift - the multiplier a for dF/dU_t
1876 . x - coordinates of the current point
1877 . numConstants - number of constant parameters
1878 . constants - constant parameters
1879 - g0 - output values at the current point
1880 
1881   Level: intermediate
1882 
1883 .seealso: PetscDSSetJacobian()
1884 @*/
1885 PetscErrorCode PetscDSGetDynamicJacobian(PetscDS ds, PetscInt f, PetscInt g,
1886                                          void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1887                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1888                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1889                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1890                                          void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1891                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1892                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1893                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1894                                          void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1895                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1896                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1897                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1898                                          void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1899                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1900                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1901                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1902 {
1903   PetscPointJac *tmp0, *tmp1, *tmp2, *tmp3;
1904   PetscInt       n0, n1, n2, n3;
1905 
1906   PetscFunctionBegin;
1907   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1908   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
1909   PetscCheckFalse((g < 0) || (g >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
1910   PetscCall(PetscWeakFormGetDynamicJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
1911   *g0  = tmp0 ? tmp0[0] : NULL;
1912   *g1  = tmp1 ? tmp1[0] : NULL;
1913   *g2  = tmp2 ? tmp2[0] : NULL;
1914   *g3  = tmp3 ? tmp3[0] : NULL;
1915   PetscFunctionReturn(0);
1916 }
1917 
1918 /*@C
1919   PetscDSSetDynamicJacobian - Set the pointwise dynamic Jacobian, dF/du_t, function for given test and basis fields
1920 
1921   Not collective
1922 
1923   Input Parameters:
1924 + ds - The PetscDS
1925 . f  - The test field number
1926 . g  - The field number
1927 . g0 - integrand for the test and basis function term
1928 . g1 - integrand for the test function and basis function gradient term
1929 . g2 - integrand for the test function gradient and basis function term
1930 - g3 - integrand for the test function gradient and basis function gradient term
1931 
1932   Note: We are using a first order FEM model for the weak form:
1933 
1934   \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
1935 
1936 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1937 
1938 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1939 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1940 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1941 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1942 
1943 + dim - the spatial dimension
1944 . Nf - the number of fields
1945 . uOff - the offset into u[] and u_t[] for each field
1946 . uOff_x - the offset into u_x[] for each field
1947 . u - each field evaluated at the current point
1948 . u_t - the time derivative of each field evaluated at the current point
1949 . u_x - the gradient of each field evaluated at the current point
1950 . aOff - the offset into a[] and a_t[] for each auxiliary field
1951 . aOff_x - the offset into a_x[] for each auxiliary field
1952 . a - each auxiliary field evaluated at the current point
1953 . a_t - the time derivative of each auxiliary field evaluated at the current point
1954 . a_x - the gradient of auxiliary each field evaluated at the current point
1955 . t - current time
1956 . u_tShift - the multiplier a for dF/dU_t
1957 . x - coordinates of the current point
1958 . numConstants - number of constant parameters
1959 . constants - constant parameters
1960 - g0 - output values at the current point
1961 
1962   Level: intermediate
1963 
1964 .seealso: PetscDSGetJacobian()
1965 @*/
1966 PetscErrorCode PetscDSSetDynamicJacobian(PetscDS ds, PetscInt f, PetscInt g,
1967                                          void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1968                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1969                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1970                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1971                                          void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1972                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1973                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1974                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1975                                          void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1976                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1977                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1978                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1979                                          void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1980                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1981                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1982                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1983 {
1984   PetscFunctionBegin;
1985   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
1986   if (g0) PetscValidFunction(g0, 4);
1987   if (g1) PetscValidFunction(g1, 5);
1988   if (g2) PetscValidFunction(g2, 6);
1989   if (g3) PetscValidFunction(g3, 7);
1990   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1991   PetscCheckFalse(g < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1992   PetscCall(PetscWeakFormSetIndexDynamicJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
1993   PetscFunctionReturn(0);
1994 }
1995 
1996 /*@C
1997   PetscDSGetRiemannSolver - Returns the Riemann solver for the given field
1998 
1999   Not collective
2000 
2001   Input Parameters:
2002 + ds - The PetscDS object
2003 - f  - The field number
2004 
2005   Output Parameter:
2006 . r    - Riemann solver
2007 
2008   Calling sequence for r:
2009 
2010 $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)
2011 
2012 + dim  - The spatial dimension
2013 . Nf   - The number of fields
2014 . x    - The coordinates at a point on the interface
2015 . n    - The normal vector to the interface
2016 . uL   - The state vector to the left of the interface
2017 . uR   - The state vector to the right of the interface
2018 . flux - output array of flux through the interface
2019 . numConstants - number of constant parameters
2020 . constants - constant parameters
2021 - ctx  - optional user context
2022 
2023   Level: intermediate
2024 
2025 .seealso: PetscDSSetRiemannSolver()
2026 @*/
2027 PetscErrorCode PetscDSGetRiemannSolver(PetscDS ds, PetscInt f,
2028                                        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))
2029 {
2030   PetscRiemannFunc *tmp;
2031   PetscInt          n;
2032 
2033   PetscFunctionBegin;
2034   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2035   PetscValidPointer(r, 3);
2036   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
2037   PetscCall(PetscWeakFormGetRiemannSolver(ds->wf, NULL, 0, f, 0, &n, &tmp));
2038   *r   = tmp ? tmp[0] : NULL;
2039   PetscFunctionReturn(0);
2040 }
2041 
2042 /*@C
2043   PetscDSSetRiemannSolver - Sets the Riemann solver for the given field
2044 
2045   Not collective
2046 
2047   Input Parameters:
2048 + ds - The PetscDS object
2049 . f  - The field number
2050 - r  - Riemann solver
2051 
2052   Calling sequence for r:
2053 
2054 $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)
2055 
2056 + dim  - The spatial dimension
2057 . Nf   - The number of fields
2058 . x    - The coordinates at a point on the interface
2059 . n    - The normal vector to the interface
2060 . uL   - The state vector to the left of the interface
2061 . uR   - The state vector to the right of the interface
2062 . flux - output array of flux through the interface
2063 . numConstants - number of constant parameters
2064 . constants - constant parameters
2065 - ctx  - optional user context
2066 
2067   Level: intermediate
2068 
2069 .seealso: PetscDSGetRiemannSolver()
2070 @*/
2071 PetscErrorCode PetscDSSetRiemannSolver(PetscDS ds, PetscInt f,
2072                                        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))
2073 {
2074   PetscFunctionBegin;
2075   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2076   if (r) PetscValidFunction(r, 3);
2077   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2078   PetscCall(PetscWeakFormSetIndexRiemannSolver(ds->wf, NULL, 0, f, 0, 0, r));
2079   PetscFunctionReturn(0);
2080 }
2081 
2082 /*@C
2083   PetscDSGetUpdate - Get the pointwise update function for a given field
2084 
2085   Not collective
2086 
2087   Input Parameters:
2088 + ds - The PetscDS
2089 - f  - The field number
2090 
2091   Output Parameter:
2092 . update - update function
2093 
2094   Note: The calling sequence for the callback update is given by:
2095 
2096 $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2097 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2098 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2099 $        PetscReal t, const PetscReal x[], PetscScalar uNew[])
2100 
2101 + dim - the spatial dimension
2102 . Nf - the number of fields
2103 . uOff - the offset into u[] and u_t[] for each field
2104 . uOff_x - the offset into u_x[] for each field
2105 . u - each field evaluated at the current point
2106 . u_t - the time derivative of each field evaluated at the current point
2107 . u_x - the gradient of each field evaluated at the current point
2108 . aOff - the offset into a[] and a_t[] for each auxiliary field
2109 . aOff_x - the offset into a_x[] for each auxiliary field
2110 . a - each auxiliary field evaluated at the current point
2111 . a_t - the time derivative of each auxiliary field evaluated at the current point
2112 . a_x - the gradient of auxiliary each field evaluated at the current point
2113 . t - current time
2114 . x - coordinates of the current point
2115 - uNew - new value for field at the current point
2116 
2117   Level: intermediate
2118 
2119 .seealso: PetscDSSetUpdate(), PetscDSSetResidual()
2120 @*/
2121 PetscErrorCode PetscDSGetUpdate(PetscDS ds, PetscInt f,
2122                                   void (**update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2123                                                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2124                                                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2125                                                   PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
2126 {
2127   PetscFunctionBegin;
2128   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2129   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
2130   if (update) {PetscValidPointer(update, 3); *update = ds->update[f];}
2131   PetscFunctionReturn(0);
2132 }
2133 
2134 /*@C
2135   PetscDSSetUpdate - Set the pointwise update function for a given field
2136 
2137   Not collective
2138 
2139   Input Parameters:
2140 + ds     - The PetscDS
2141 . f      - The field number
2142 - update - update function
2143 
2144   Note: The calling sequence for the callback update is given by:
2145 
2146 $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2147 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2148 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2149 $        PetscReal t, const PetscReal x[], PetscScalar uNew[])
2150 
2151 + dim - the spatial dimension
2152 . Nf - the number of fields
2153 . uOff - the offset into u[] and u_t[] for each field
2154 . uOff_x - the offset into u_x[] for each field
2155 . u - each field evaluated at the current point
2156 . u_t - the time derivative of each field evaluated at the current point
2157 . u_x - the gradient of each field evaluated at the current point
2158 . aOff - the offset into a[] and a_t[] for each auxiliary field
2159 . aOff_x - the offset into a_x[] for each auxiliary field
2160 . a - each auxiliary field evaluated at the current point
2161 . a_t - the time derivative of each auxiliary field evaluated at the current point
2162 . a_x - the gradient of auxiliary each field evaluated at the current point
2163 . t - current time
2164 . x - coordinates of the current point
2165 - uNew - new field values at the current point
2166 
2167   Level: intermediate
2168 
2169 .seealso: PetscDSGetResidual()
2170 @*/
2171 PetscErrorCode PetscDSSetUpdate(PetscDS ds, PetscInt f,
2172                                 void (*update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2173                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2174                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2175                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
2176 {
2177   PetscFunctionBegin;
2178   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2179   if (update) PetscValidFunction(update, 3);
2180   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2181   PetscCall(PetscDSEnlarge_Static(ds, f+1));
2182   ds->update[f] = update;
2183   PetscFunctionReturn(0);
2184 }
2185 
2186 PetscErrorCode PetscDSGetContext(PetscDS ds, PetscInt f, void *ctx)
2187 {
2188   PetscFunctionBegin;
2189   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2190   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
2191   PetscValidPointer(ctx, 3);
2192   *(void**)ctx = ds->ctx[f];
2193   PetscFunctionReturn(0);
2194 }
2195 
2196 PetscErrorCode PetscDSSetContext(PetscDS ds, PetscInt f, void *ctx)
2197 {
2198   PetscFunctionBegin;
2199   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2200   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2201   PetscCall(PetscDSEnlarge_Static(ds, f+1));
2202   ds->ctx[f] = ctx;
2203   PetscFunctionReturn(0);
2204 }
2205 
2206 /*@C
2207   PetscDSGetBdResidual - Get the pointwise boundary residual function for a given test field
2208 
2209   Not collective
2210 
2211   Input Parameters:
2212 + ds - The PetscDS
2213 - f  - The test field number
2214 
2215   Output Parameters:
2216 + f0 - boundary integrand for the test function term
2217 - f1 - boundary integrand for the test function gradient term
2218 
2219   Note: We are using a first order FEM model for the weak form:
2220 
2221   \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
2222 
2223 The calling sequence for the callbacks f0 and f1 is given by:
2224 
2225 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2226 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2227 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2228 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
2229 
2230 + dim - the spatial dimension
2231 . Nf - the number of fields
2232 . uOff - the offset into u[] and u_t[] for each field
2233 . uOff_x - the offset into u_x[] for each field
2234 . u - each field evaluated at the current point
2235 . u_t - the time derivative of each field evaluated at the current point
2236 . u_x - the gradient of each field evaluated at the current point
2237 . aOff - the offset into a[] and a_t[] for each auxiliary field
2238 . aOff_x - the offset into a_x[] for each auxiliary field
2239 . a - each auxiliary field evaluated at the current point
2240 . a_t - the time derivative of each auxiliary field evaluated at the current point
2241 . a_x - the gradient of auxiliary each field evaluated at the current point
2242 . t - current time
2243 . x - coordinates of the current point
2244 . n - unit normal at the current point
2245 . numConstants - number of constant parameters
2246 . constants - constant parameters
2247 - f0 - output values at the current point
2248 
2249   Level: intermediate
2250 
2251 .seealso: PetscDSSetBdResidual()
2252 @*/
2253 PetscErrorCode PetscDSGetBdResidual(PetscDS ds, PetscInt f,
2254                                     void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2255                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2256                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2257                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
2258                                     void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2259                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2260                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2261                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
2262 {
2263   PetscBdPointFunc *tmp0, *tmp1;
2264   PetscInt          n0, n1;
2265 
2266   PetscFunctionBegin;
2267   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2268   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
2269   PetscCall(PetscWeakFormGetBdResidual(ds->wf, NULL, 0, f, 0, &n0, &tmp0, &n1, &tmp1));
2270   *f0  = tmp0 ? tmp0[0] : NULL;
2271   *f1  = tmp1 ? tmp1[0] : NULL;
2272   PetscFunctionReturn(0);
2273 }
2274 
2275 /*@C
2276   PetscDSSetBdResidual - Get the pointwise boundary residual function for a given test field
2277 
2278   Not collective
2279 
2280   Input Parameters:
2281 + ds - The PetscDS
2282 . f  - The test field number
2283 . f0 - boundary integrand for the test function term
2284 - f1 - boundary integrand for the test function gradient term
2285 
2286   Note: We are using a first order FEM model for the weak form:
2287 
2288   \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
2289 
2290 The calling sequence for the callbacks f0 and f1 is given by:
2291 
2292 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2293 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2294 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2295 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
2296 
2297 + dim - the spatial dimension
2298 . Nf - the number of fields
2299 . uOff - the offset into u[] and u_t[] for each field
2300 . uOff_x - the offset into u_x[] for each field
2301 . u - each field evaluated at the current point
2302 . u_t - the time derivative of each field evaluated at the current point
2303 . u_x - the gradient of each field evaluated at the current point
2304 . aOff - the offset into a[] and a_t[] for each auxiliary field
2305 . aOff_x - the offset into a_x[] for each auxiliary field
2306 . a - each auxiliary field evaluated at the current point
2307 . a_t - the time derivative of each auxiliary field evaluated at the current point
2308 . a_x - the gradient of auxiliary each field evaluated at the current point
2309 . t - current time
2310 . x - coordinates of the current point
2311 . n - unit normal at the current point
2312 . numConstants - number of constant parameters
2313 . constants - constant parameters
2314 - f0 - output values at the current point
2315 
2316   Level: intermediate
2317 
2318 .seealso: PetscDSGetBdResidual()
2319 @*/
2320 PetscErrorCode PetscDSSetBdResidual(PetscDS ds, PetscInt f,
2321                                     void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2322                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2323                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2324                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
2325                                     void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2326                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2327                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2328                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
2329 {
2330   PetscFunctionBegin;
2331   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2332   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2333   PetscCall(PetscWeakFormSetIndexBdResidual(ds->wf, NULL, 0, f, 0, 0, f0, 0, f1));
2334   PetscFunctionReturn(0);
2335 }
2336 
2337 /*@
2338   PetscDSHasBdJacobian - Signals that boundary Jacobian functions have been set
2339 
2340   Not collective
2341 
2342   Input Parameter:
2343 . ds - The PetscDS
2344 
2345   Output Parameter:
2346 . hasBdJac - flag that pointwise function for the boundary Jacobian has been set
2347 
2348   Level: intermediate
2349 
2350 .seealso: PetscDSHasJacobian(), PetscDSSetBdJacobian(), PetscDSGetBdJacobian()
2351 @*/
2352 PetscErrorCode PetscDSHasBdJacobian(PetscDS ds, PetscBool *hasBdJac)
2353 {
2354   PetscFunctionBegin;
2355   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2356   PetscValidBoolPointer(hasBdJac, 2);
2357   PetscCall(PetscWeakFormHasBdJacobian(ds->wf, hasBdJac));
2358   PetscFunctionReturn(0);
2359 }
2360 
2361 /*@C
2362   PetscDSGetBdJacobian - Get the pointwise boundary Jacobian function for given test and basis field
2363 
2364   Not collective
2365 
2366   Input Parameters:
2367 + ds - The PetscDS
2368 . f  - The test field number
2369 - g  - The field number
2370 
2371   Output Parameters:
2372 + g0 - integrand for the test and basis function term
2373 . g1 - integrand for the test function and basis function gradient term
2374 . g2 - integrand for the test function gradient and basis function term
2375 - g3 - integrand for the test function gradient and basis function gradient term
2376 
2377   Note: We are using a first order FEM model for the weak form:
2378 
2379   \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
2380 
2381 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2382 
2383 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2384 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2385 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2386 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])
2387 
2388 + dim - the spatial dimension
2389 . Nf - the number of fields
2390 . uOff - the offset into u[] and u_t[] for each field
2391 . uOff_x - the offset into u_x[] for each field
2392 . u - each field evaluated at the current point
2393 . u_t - the time derivative of each field evaluated at the current point
2394 . u_x - the gradient of each field evaluated at the current point
2395 . aOff - the offset into a[] and a_t[] for each auxiliary field
2396 . aOff_x - the offset into a_x[] for each auxiliary field
2397 . a - each auxiliary field evaluated at the current point
2398 . a_t - the time derivative of each auxiliary field evaluated at the current point
2399 . a_x - the gradient of auxiliary each field evaluated at the current point
2400 . t - current time
2401 . u_tShift - the multiplier a for dF/dU_t
2402 . x - coordinates of the current point
2403 . n - normal at the current point
2404 . numConstants - number of constant parameters
2405 . constants - constant parameters
2406 - g0 - output values at the current point
2407 
2408   Level: intermediate
2409 
2410 .seealso: PetscDSSetBdJacobian()
2411 @*/
2412 PetscErrorCode PetscDSGetBdJacobian(PetscDS ds, PetscInt f, PetscInt g,
2413                                     void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2414                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2415                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2416                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2417                                     void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2418                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2419                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2420                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2421                                     void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2422                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2423                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2424                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2425                                     void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2426                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2427                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2428                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2429 {
2430   PetscBdPointJac *tmp0, *tmp1, *tmp2, *tmp3;
2431   PetscInt         n0, n1, n2, n3;
2432 
2433   PetscFunctionBegin;
2434   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2435   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
2436   PetscCheckFalse((g < 0) || (g >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
2437   PetscCall(PetscWeakFormGetBdJacobian(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
2438   *g0  = tmp0 ? tmp0[0] : NULL;
2439   *g1  = tmp1 ? tmp1[0] : NULL;
2440   *g2  = tmp2 ? tmp2[0] : NULL;
2441   *g3  = tmp3 ? tmp3[0] : NULL;
2442   PetscFunctionReturn(0);
2443 }
2444 
2445 /*@C
2446   PetscDSSetBdJacobian - Set the pointwise boundary Jacobian function for given test and basis field
2447 
2448   Not collective
2449 
2450   Input Parameters:
2451 + ds - The PetscDS
2452 . f  - The test field number
2453 . g  - The field number
2454 . g0 - integrand for the test and basis function term
2455 . g1 - integrand for the test function and basis function gradient term
2456 . g2 - integrand for the test function gradient and basis function term
2457 - g3 - integrand for the test function gradient and basis function gradient term
2458 
2459   Note: We are using a first order FEM model for the weak form:
2460 
2461   \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
2462 
2463 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2464 
2465 $ 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, const PetscReal x[], const PetscReal n[], PetscScalar g0[])
2469 
2470 + dim - the spatial dimension
2471 . Nf - the number of fields
2472 . uOff - the offset into u[] and u_t[] for each field
2473 . uOff_x - the offset into u_x[] for each field
2474 . u - each field evaluated at the current point
2475 . u_t - the time derivative of each field evaluated at the current point
2476 . u_x - the gradient of each field evaluated at the current point
2477 . aOff - the offset into a[] and a_t[] for each auxiliary field
2478 . aOff_x - the offset into a_x[] for each auxiliary field
2479 . a - each auxiliary field evaluated at the current point
2480 . a_t - the time derivative of each auxiliary field evaluated at the current point
2481 . a_x - the gradient of auxiliary each field evaluated at the current point
2482 . t - current time
2483 . u_tShift - the multiplier a for dF/dU_t
2484 . x - coordinates of the current point
2485 . n - normal at the current point
2486 . numConstants - number of constant parameters
2487 . constants - constant parameters
2488 - g0 - output values at the current point
2489 
2490   Level: intermediate
2491 
2492 .seealso: PetscDSGetBdJacobian()
2493 @*/
2494 PetscErrorCode PetscDSSetBdJacobian(PetscDS ds, PetscInt f, PetscInt g,
2495                                     void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2496                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2497                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2498                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2499                                     void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2500                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2501                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2502                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2503                                     void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2504                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2505                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2506                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2507                                     void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2508                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2509                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2510                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2511 {
2512   PetscFunctionBegin;
2513   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2514   if (g0) PetscValidFunction(g0, 4);
2515   if (g1) PetscValidFunction(g1, 5);
2516   if (g2) PetscValidFunction(g2, 6);
2517   if (g3) PetscValidFunction(g3, 7);
2518   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2519   PetscCheckFalse(g < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
2520   PetscCall(PetscWeakFormSetIndexBdJacobian(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
2521   PetscFunctionReturn(0);
2522 }
2523 
2524 /*@
2525   PetscDSHasBdJacobianPreconditioner - Signals that boundary Jacobian preconditioner functions have been set
2526 
2527   Not collective
2528 
2529   Input Parameter:
2530 . ds - The PetscDS
2531 
2532   Output Parameter:
2533 . hasBdJac - flag that pointwise function for the boundary Jacobian preconditioner has been set
2534 
2535   Level: intermediate
2536 
2537 .seealso: PetscDSHasJacobian(), PetscDSSetBdJacobian(), PetscDSGetBdJacobian()
2538 @*/
2539 PetscErrorCode PetscDSHasBdJacobianPreconditioner(PetscDS ds, PetscBool *hasBdJacPre)
2540 {
2541   PetscFunctionBegin;
2542   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2543   PetscValidBoolPointer(hasBdJacPre, 2);
2544   PetscCall(PetscWeakFormHasBdJacobianPreconditioner(ds->wf, hasBdJacPre));
2545   PetscFunctionReturn(0);
2546 }
2547 
2548 /*@C
2549   PetscDSGetBdJacobianPreconditioner - Get the pointwise boundary Jacobian preconditioner function for given test and basis field
2550 
2551   Not collective
2552 
2553   Input Parameters:
2554 + ds - The PetscDS
2555 . f  - The test field number
2556 - g  - The field number
2557 
2558   Output Parameters:
2559 + g0 - integrand for the test and basis function term
2560 . g1 - integrand for the test function and basis function gradient term
2561 . g2 - integrand for the test function gradient and basis function term
2562 - g3 - integrand for the test function gradient and basis function gradient term
2563 
2564   Note: We are using a first order FEM model for the weak form:
2565 
2566   \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
2567 
2568 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2569 
2570 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2571 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2572 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2573 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
2574 
2575 + dim - the spatial dimension
2576 . Nf - the number of fields
2577 . NfAux - the number of auxiliary fields
2578 . uOff - the offset into u[] and u_t[] for each field
2579 . uOff_x - the offset into u_x[] for each field
2580 . u - each field evaluated at the current point
2581 . u_t - the time derivative of each field evaluated at the current point
2582 . u_x - the gradient of each field evaluated at the current point
2583 . aOff - the offset into a[] and a_t[] for each auxiliary field
2584 . aOff_x - the offset into a_x[] for each auxiliary field
2585 . a - each auxiliary field evaluated at the current point
2586 . a_t - the time derivative of each auxiliary field evaluated at the current point
2587 . a_x - the gradient of auxiliary each field evaluated at the current point
2588 . t - current time
2589 . u_tShift - the multiplier a for dF/dU_t
2590 . x - coordinates of the current point
2591 . n - normal at the current point
2592 . numConstants - number of constant parameters
2593 . constants - constant parameters
2594 - g0 - output values at the current point
2595 
2596   This is not yet available in Fortran.
2597 
2598   Level: intermediate
2599 
2600 .seealso: PetscDSSetBdJacobianPreconditioner()
2601 @*/
2602 PetscErrorCode PetscDSGetBdJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g,
2603                                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2604                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2605                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2606                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2607                                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2608                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2609                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2610                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2611                                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2612                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2613                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2614                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2615                                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2616                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2617                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2618                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2619 {
2620   PetscBdPointJac *tmp0, *tmp1, *tmp2, *tmp3;
2621   PetscInt         n0, n1, n2, n3;
2622 
2623   PetscFunctionBegin;
2624   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2625   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
2626   PetscCheckFalse((g < 0) || (g >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, ds->Nf);
2627   PetscCall(PetscWeakFormGetBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
2628   *g0  = tmp0 ? tmp0[0] : NULL;
2629   *g1  = tmp1 ? tmp1[0] : NULL;
2630   *g2  = tmp2 ? tmp2[0] : NULL;
2631   *g3  = tmp3 ? tmp3[0] : NULL;
2632   PetscFunctionReturn(0);
2633 }
2634 
2635 /*@C
2636   PetscDSSetBdJacobianPreconditioner - Set the pointwise boundary Jacobian preconditioner function for given test and basis field
2637 
2638   Not collective
2639 
2640   Input Parameters:
2641 + ds - The PetscDS
2642 . f  - The test field number
2643 . g  - The field number
2644 . g0 - integrand for the test and basis function term
2645 . g1 - integrand for the test function and basis function gradient term
2646 . g2 - integrand for the test function gradient and basis function term
2647 - g3 - integrand for the test function gradient and basis function gradient term
2648 
2649   Note: We are using a first order FEM model for the weak form:
2650 
2651   \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
2652 
2653 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2654 
2655 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2656 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2657 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2658 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
2659 
2660 + dim - the spatial dimension
2661 . Nf - the number of fields
2662 . NfAux - the number of auxiliary fields
2663 . uOff - the offset into u[] and u_t[] for each field
2664 . uOff_x - the offset into u_x[] for each field
2665 . u - each field evaluated at the current point
2666 . u_t - the time derivative of each field evaluated at the current point
2667 . u_x - the gradient of each field evaluated at the current point
2668 . aOff - the offset into a[] and a_t[] for each auxiliary field
2669 . aOff_x - the offset into a_x[] for each auxiliary field
2670 . a - each auxiliary field evaluated at the current point
2671 . a_t - the time derivative of each auxiliary field evaluated at the current point
2672 . a_x - the gradient of auxiliary each field evaluated at the current point
2673 . t - current time
2674 . u_tShift - the multiplier a for dF/dU_t
2675 . x - coordinates of the current point
2676 . n - normal at the current point
2677 . numConstants - number of constant parameters
2678 . constants - constant parameters
2679 - g0 - output values at the current point
2680 
2681   This is not yet available in Fortran.
2682 
2683   Level: intermediate
2684 
2685 .seealso: PetscDSGetBdJacobianPreconditioner()
2686 @*/
2687 PetscErrorCode PetscDSSetBdJacobianPreconditioner(PetscDS ds, PetscInt f, PetscInt g,
2688                                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2689                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2690                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2691                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2692                                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2693                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2694                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2695                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2696                                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2697                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2698                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2699                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2700                                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2701                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2702                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2703                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2704 {
2705   PetscFunctionBegin;
2706   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2707   if (g0) PetscValidFunction(g0, 4);
2708   if (g1) PetscValidFunction(g1, 5);
2709   if (g2) PetscValidFunction(g2, 6);
2710   if (g3) PetscValidFunction(g3, 7);
2711   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2712   PetscCheckFalse(g < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
2713   PetscCall(PetscWeakFormSetIndexBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
2714   PetscFunctionReturn(0);
2715 }
2716 
2717 /*@C
2718   PetscDSGetExactSolution - Get the pointwise exact solution function for a given test field
2719 
2720   Not collective
2721 
2722   Input Parameters:
2723 + prob - The PetscDS
2724 - f    - The test field number
2725 
2726   Output Parameters:
2727 + exactSol - exact solution for the test field
2728 - exactCtx - exact solution context
2729 
2730   Note: The calling sequence for the solution functions is given by:
2731 
2732 $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2733 
2734 + dim - the spatial dimension
2735 . t - current time
2736 . x - coordinates of the current point
2737 . Nc - the number of field components
2738 . u - the solution field evaluated at the current point
2739 - ctx - a user context
2740 
2741   Level: intermediate
2742 
2743 .seealso: PetscDSSetExactSolution(), PetscDSGetExactSolutionTimeDerivative()
2744 @*/
2745 PetscErrorCode PetscDSGetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
2746 {
2747   PetscFunctionBegin;
2748   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2749   PetscCheckFalse((f < 0) || (f >= prob->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
2750   if (sol) {PetscValidPointer(sol, 3); *sol = prob->exactSol[f];}
2751   if (ctx) {PetscValidPointer(ctx, 4); *ctx = prob->exactCtx[f];}
2752   PetscFunctionReturn(0);
2753 }
2754 
2755 /*@C
2756   PetscDSSetExactSolution - Set the pointwise exact solution function for a given test field
2757 
2758   Not collective
2759 
2760   Input Parameters:
2761 + prob - The PetscDS
2762 . f    - The test field number
2763 . sol  - solution function for the test fields
2764 - ctx  - solution context or NULL
2765 
2766   Note: The calling sequence for solution functions is given by:
2767 
2768 $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2769 
2770 + dim - the spatial dimension
2771 . t - current time
2772 . x - coordinates of the current point
2773 . Nc - the number of field components
2774 . u - the solution field evaluated at the current point
2775 - ctx - a user context
2776 
2777   Level: intermediate
2778 
2779 .seealso: PetscDSGetExactSolution()
2780 @*/
2781 PetscErrorCode PetscDSSetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
2782 {
2783   PetscFunctionBegin;
2784   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2785   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2786   PetscCall(PetscDSEnlarge_Static(prob, f+1));
2787   if (sol) {PetscValidFunction(sol, 3); prob->exactSol[f] = sol;}
2788   if (ctx) {PetscValidFunction(ctx, 4); prob->exactCtx[f] = ctx;}
2789   PetscFunctionReturn(0);
2790 }
2791 
2792 /*@C
2793   PetscDSGetExactSolutionTimeDerivative - Get the pointwise time derivative of the exact solution function for a given test field
2794 
2795   Not collective
2796 
2797   Input Parameters:
2798 + prob - The PetscDS
2799 - f    - The test field number
2800 
2801   Output Parameters:
2802 + exactSol - time derivative of the exact solution for the test field
2803 - exactCtx - time derivative of the exact solution context
2804 
2805   Note: The calling sequence for the solution functions is given by:
2806 
2807 $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2808 
2809 + dim - the spatial dimension
2810 . t - current time
2811 . x - coordinates of the current point
2812 . Nc - the number of field components
2813 . u - the solution field evaluated at the current point
2814 - ctx - a user context
2815 
2816   Level: intermediate
2817 
2818 .seealso: PetscDSSetExactSolutionTimeDerivative(), PetscDSGetExactSolution()
2819 @*/
2820 PetscErrorCode PetscDSGetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
2821 {
2822   PetscFunctionBegin;
2823   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2824   PetscCheckFalse((f < 0) || (f >= prob->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
2825   if (sol) {PetscValidPointer(sol, 3); *sol = prob->exactSol_t[f];}
2826   if (ctx) {PetscValidPointer(ctx, 4); *ctx = prob->exactCtx_t[f];}
2827   PetscFunctionReturn(0);
2828 }
2829 
2830 /*@C
2831   PetscDSSetExactSolutionTimeDerivative - Set the pointwise time derivative of the exact solution function for a given test field
2832 
2833   Not collective
2834 
2835   Input Parameters:
2836 + prob - The PetscDS
2837 . f    - The test field number
2838 . sol  - time derivative of the solution function for the test fields
2839 - ctx  - time derivative of the solution context or NULL
2840 
2841   Note: The calling sequence for solution functions is given by:
2842 
2843 $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2844 
2845 + dim - the spatial dimension
2846 . t - current time
2847 . x - coordinates of the current point
2848 . Nc - the number of field components
2849 . u - the solution field evaluated at the current point
2850 - ctx - a user context
2851 
2852   Level: intermediate
2853 
2854 .seealso: PetscDSGetExactSolutionTimeDerivative(), PetscDSSetExactSolution()
2855 @*/
2856 PetscErrorCode PetscDSSetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
2857 {
2858   PetscFunctionBegin;
2859   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2860   PetscCheckFalse(f < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2861   PetscCall(PetscDSEnlarge_Static(prob, f+1));
2862   if (sol) {PetscValidFunction(sol, 3); prob->exactSol_t[f] = sol;}
2863   if (ctx) {PetscValidFunction(ctx, 4); prob->exactCtx_t[f] = ctx;}
2864   PetscFunctionReturn(0);
2865 }
2866 
2867 /*@C
2868   PetscDSGetConstants - Returns the array of constants passed to point functions
2869 
2870   Not collective
2871 
2872   Input Parameter:
2873 . prob - The PetscDS object
2874 
2875   Output Parameters:
2876 + numConstants - The number of constants
2877 - constants    - The array of constants, NULL if there are none
2878 
2879   Level: intermediate
2880 
2881 .seealso: PetscDSSetConstants(), PetscDSCreate()
2882 @*/
2883 PetscErrorCode PetscDSGetConstants(PetscDS prob, PetscInt *numConstants, const PetscScalar *constants[])
2884 {
2885   PetscFunctionBegin;
2886   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2887   if (numConstants) {PetscValidIntPointer(numConstants, 2); *numConstants = prob->numConstants;}
2888   if (constants)    {PetscValidPointer(constants, 3);    *constants    = prob->constants;}
2889   PetscFunctionReturn(0);
2890 }
2891 
2892 /*@C
2893   PetscDSSetConstants - Set the array of constants passed to point functions
2894 
2895   Not collective
2896 
2897   Input Parameters:
2898 + prob         - The PetscDS object
2899 . numConstants - The number of constants
2900 - constants    - The array of constants, NULL if there are none
2901 
2902   Level: intermediate
2903 
2904 .seealso: PetscDSGetConstants(), PetscDSCreate()
2905 @*/
2906 PetscErrorCode PetscDSSetConstants(PetscDS prob, PetscInt numConstants, PetscScalar constants[])
2907 {
2908   PetscFunctionBegin;
2909   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2910   if (numConstants != prob->numConstants) {
2911     PetscCall(PetscFree(prob->constants));
2912     prob->numConstants = numConstants;
2913     if (prob->numConstants) {
2914       PetscCall(PetscMalloc1(prob->numConstants, &prob->constants));
2915     } else {
2916       prob->constants = NULL;
2917     }
2918   }
2919   if (prob->numConstants) {
2920     PetscValidScalarPointer(constants, 3);
2921     PetscCall(PetscArraycpy(prob->constants, constants, prob->numConstants));
2922   }
2923   PetscFunctionReturn(0);
2924 }
2925 
2926 /*@
2927   PetscDSGetFieldIndex - Returns the index of the given field
2928 
2929   Not collective
2930 
2931   Input Parameters:
2932 + prob - The PetscDS object
2933 - disc - The discretization object
2934 
2935   Output Parameter:
2936 . f - The field number
2937 
2938   Level: beginner
2939 
2940 .seealso: PetscGetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
2941 @*/
2942 PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
2943 {
2944   PetscInt g;
2945 
2946   PetscFunctionBegin;
2947   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2948   PetscValidIntPointer(f, 3);
2949   *f = -1;
2950   for (g = 0; g < prob->Nf; ++g) {if (disc == prob->disc[g]) break;}
2951   PetscCheckFalse(g == prob->Nf,PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
2952   *f = g;
2953   PetscFunctionReturn(0);
2954 }
2955 
2956 /*@
2957   PetscDSGetFieldSize - Returns the size of the given field in the full space basis
2958 
2959   Not collective
2960 
2961   Input Parameters:
2962 + prob - The PetscDS object
2963 - f - The field number
2964 
2965   Output Parameter:
2966 . size - The size
2967 
2968   Level: beginner
2969 
2970 .seealso: PetscDSGetFieldOffset(), PetscDSGetNumFields(), PetscDSCreate()
2971 @*/
2972 PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
2973 {
2974   PetscFunctionBegin;
2975   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2976   PetscValidIntPointer(size, 3);
2977   PetscCheckFalse((f < 0) || (f >= prob->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
2978   PetscCall(PetscDSSetUp(prob));
2979   *size = prob->Nb[f];
2980   PetscFunctionReturn(0);
2981 }
2982 
2983 /*@
2984   PetscDSGetFieldOffset - Returns the offset of the given field in the full space basis
2985 
2986   Not collective
2987 
2988   Input Parameters:
2989 + prob - The PetscDS object
2990 - f - The field number
2991 
2992   Output Parameter:
2993 . off - The offset
2994 
2995   Level: beginner
2996 
2997 .seealso: PetscDSGetFieldSize(), PetscDSGetNumFields(), PetscDSCreate()
2998 @*/
2999 PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
3000 {
3001   PetscInt       size, g;
3002 
3003   PetscFunctionBegin;
3004   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3005   PetscValidIntPointer(off, 3);
3006   PetscCheckFalse((f < 0) || (f >= prob->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
3007   *off = 0;
3008   for (g = 0; g < f; ++g) {
3009     PetscCall(PetscDSGetFieldSize(prob, g, &size));
3010     *off += size;
3011   }
3012   PetscFunctionReturn(0);
3013 }
3014 
3015 /*@
3016   PetscDSGetFieldOffsetCohesive - Returns the offset of the given field in the full space basis on a cohesive cell
3017 
3018   Not collective
3019 
3020   Input Parameters:
3021 + prob - The PetscDS object
3022 - f - The field number
3023 
3024   Output Parameter:
3025 . off - The offset
3026 
3027   Level: beginner
3028 
3029 .seealso: PetscDSGetFieldSize(), PetscDSGetNumFields(), PetscDSCreate()
3030 @*/
3031 PetscErrorCode PetscDSGetFieldOffsetCohesive(PetscDS ds, PetscInt f, PetscInt *off)
3032 {
3033   PetscInt       size, g;
3034 
3035   PetscFunctionBegin;
3036   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3037   PetscValidIntPointer(off, 3);
3038   PetscCheckFalse((f < 0) || (f >= ds->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, ds->Nf);
3039   *off = 0;
3040   for (g = 0; g < f; ++g) {
3041     PetscBool cohesive;
3042 
3043     PetscCall(PetscDSGetCohesive(ds, g, &cohesive));
3044     PetscCall(PetscDSGetFieldSize(ds, g, &size));
3045     *off += cohesive ? size : size*2;
3046   }
3047   PetscFunctionReturn(0);
3048 }
3049 
3050 /*@
3051   PetscDSGetDimensions - Returns the size of the approximation space for each field on an evaluation point
3052 
3053   Not collective
3054 
3055   Input Parameter:
3056 . prob - The PetscDS object
3057 
3058   Output Parameter:
3059 . dimensions - The number of dimensions
3060 
3061   Level: beginner
3062 
3063 .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
3064 @*/
3065 PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
3066 {
3067   PetscFunctionBegin;
3068   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3069   PetscCall(PetscDSSetUp(prob));
3070   PetscValidPointer(dimensions, 2);
3071   *dimensions = prob->Nb;
3072   PetscFunctionReturn(0);
3073 }
3074 
3075 /*@
3076   PetscDSGetComponents - Returns the number of components for each field on an evaluation point
3077 
3078   Not collective
3079 
3080   Input Parameter:
3081 . prob - The PetscDS object
3082 
3083   Output Parameter:
3084 . components - The number of components
3085 
3086   Level: beginner
3087 
3088 .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
3089 @*/
3090 PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
3091 {
3092   PetscFunctionBegin;
3093   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3094   PetscCall(PetscDSSetUp(prob));
3095   PetscValidPointer(components, 2);
3096   *components = prob->Nc;
3097   PetscFunctionReturn(0);
3098 }
3099 
3100 /*@
3101   PetscDSGetComponentOffset - Returns the offset of the given field on an evaluation point
3102 
3103   Not collective
3104 
3105   Input Parameters:
3106 + prob - The PetscDS object
3107 - f - The field number
3108 
3109   Output Parameter:
3110 . off - The offset
3111 
3112   Level: beginner
3113 
3114 .seealso: PetscDSGetNumFields(), PetscDSCreate()
3115 @*/
3116 PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
3117 {
3118   PetscFunctionBegin;
3119   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3120   PetscValidIntPointer(off, 3);
3121   PetscCheckFalse((f < 0) || (f >= prob->Nf),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, prob->Nf);
3122   PetscCall(PetscDSSetUp(prob));
3123   *off = prob->off[f];
3124   PetscFunctionReturn(0);
3125 }
3126 
3127 /*@
3128   PetscDSGetComponentOffsets - Returns the offset of each field on an evaluation point
3129 
3130   Not collective
3131 
3132   Input Parameter:
3133 . prob - The PetscDS object
3134 
3135   Output Parameter:
3136 . offsets - The offsets
3137 
3138   Level: beginner
3139 
3140 .seealso: PetscDSGetNumFields(), PetscDSCreate()
3141 @*/
3142 PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
3143 {
3144   PetscFunctionBegin;
3145   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3146   PetscValidPointer(offsets, 2);
3147   PetscCall(PetscDSSetUp(prob));
3148   *offsets = prob->off;
3149   PetscFunctionReturn(0);
3150 }
3151 
3152 /*@
3153   PetscDSGetComponentDerivativeOffsets - Returns the offset of each field derivative on an evaluation point
3154 
3155   Not collective
3156 
3157   Input Parameter:
3158 . prob - The PetscDS object
3159 
3160   Output Parameter:
3161 . offsets - The offsets
3162 
3163   Level: beginner
3164 
3165 .seealso: PetscDSGetNumFields(), PetscDSCreate()
3166 @*/
3167 PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
3168 {
3169   PetscFunctionBegin;
3170   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3171   PetscValidPointer(offsets, 2);
3172   PetscCall(PetscDSSetUp(prob));
3173   *offsets = prob->offDer;
3174   PetscFunctionReturn(0);
3175 }
3176 
3177 /*@
3178   PetscDSGetComponentOffsetsCohesive - Returns the offset of each field on an evaluation point
3179 
3180   Not collective
3181 
3182   Input Parameters:
3183 + ds - The PetscDS object
3184 - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive
3185 
3186   Output Parameter:
3187 . offsets - The offsets
3188 
3189   Level: beginner
3190 
3191 .seealso: PetscDSGetNumFields(), PetscDSCreate()
3192 @*/
3193 PetscErrorCode PetscDSGetComponentOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
3194 {
3195   PetscFunctionBegin;
3196   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3197   PetscValidPointer(offsets, 3);
3198   PetscCheck(ds->isCohesive,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
3199   PetscCheckFalse((s < 0) || (s > 2),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %D is not in [0, 2]", s);
3200   PetscCall(PetscDSSetUp(ds));
3201   *offsets = ds->offCohesive[s];
3202   PetscFunctionReturn(0);
3203 }
3204 
3205 /*@
3206   PetscDSGetComponentDerivativeOffsetsCohesive - Returns the offset of each field derivative on an evaluation point
3207 
3208   Not collective
3209 
3210   Input Parameters:
3211 + ds - The PetscDS object
3212 - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive
3213 
3214   Output Parameter:
3215 . offsets - The offsets
3216 
3217   Level: beginner
3218 
3219 .seealso: PetscDSGetNumFields(), PetscDSCreate()
3220 @*/
3221 PetscErrorCode PetscDSGetComponentDerivativeOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
3222 {
3223   PetscFunctionBegin;
3224   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3225   PetscValidPointer(offsets, 3);
3226   PetscCheck(ds->isCohesive,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
3227   PetscCheckFalse((s < 0) || (s > 2),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %D is not in [0, 2]", s);
3228   PetscCall(PetscDSSetUp(ds));
3229   *offsets = ds->offDerCohesive[s];
3230   PetscFunctionReturn(0);
3231 }
3232 
3233 /*@C
3234   PetscDSGetTabulation - Return the basis tabulation at quadrature points for the volume discretization
3235 
3236   Not collective
3237 
3238   Input Parameter:
3239 . prob - The PetscDS object
3240 
3241   Output Parameter:
3242 . T - The basis function and derivatives tabulation at quadrature points for each field
3243 
3244   Level: intermediate
3245 
3246 .seealso: PetscDSCreate()
3247 @*/
3248 PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[])
3249 {
3250   PetscFunctionBegin;
3251   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3252   PetscValidPointer(T, 2);
3253   PetscCall(PetscDSSetUp(prob));
3254   *T = prob->T;
3255   PetscFunctionReturn(0);
3256 }
3257 
3258 /*@C
3259   PetscDSGetFaceTabulation - Return the basis tabulation at quadrature points on the faces
3260 
3261   Not collective
3262 
3263   Input Parameter:
3264 . prob - The PetscDS object
3265 
3266   Output Parameter:
3267 . Tf - The basis function and derivative tabulation on each local face at quadrature points for each and field
3268 
3269   Level: intermediate
3270 
3271 .seealso: PetscDSGetTabulation(), PetscDSCreate()
3272 @*/
3273 PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
3274 {
3275   PetscFunctionBegin;
3276   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3277   PetscValidPointer(Tf, 2);
3278   PetscCall(PetscDSSetUp(prob));
3279   *Tf = prob->Tf;
3280   PetscFunctionReturn(0);
3281 }
3282 
3283 PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
3284 {
3285   PetscFunctionBegin;
3286   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3287   PetscCall(PetscDSSetUp(prob));
3288   if (u)   {PetscValidPointer(u, 2);   *u   = prob->u;}
3289   if (u_t) {PetscValidPointer(u_t, 3); *u_t = prob->u_t;}
3290   if (u_x) {PetscValidPointer(u_x, 4); *u_x = prob->u_x;}
3291   PetscFunctionReturn(0);
3292 }
3293 
3294 PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar **f0, PetscScalar **f1, PetscScalar **g0, PetscScalar **g1, PetscScalar **g2, PetscScalar **g3)
3295 {
3296   PetscFunctionBegin;
3297   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3298   PetscCall(PetscDSSetUp(prob));
3299   if (f0) {PetscValidPointer(f0, 2); *f0 = prob->f0;}
3300   if (f1) {PetscValidPointer(f1, 3); *f1 = prob->f1;}
3301   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->g0;}
3302   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->g1;}
3303   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->g2;}
3304   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->g3;}
3305   PetscFunctionReturn(0);
3306 }
3307 
3308 PetscErrorCode PetscDSGetWorkspace(PetscDS prob, PetscReal **x, PetscScalar **basisReal, PetscScalar **basisDerReal, PetscScalar **testReal, PetscScalar **testDerReal)
3309 {
3310   PetscFunctionBegin;
3311   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3312   PetscCall(PetscDSSetUp(prob));
3313   if (x)            {PetscValidPointer(x, 2);            *x            = prob->x;}
3314   if (basisReal)    {PetscValidPointer(basisReal, 3);    *basisReal    = prob->basisReal;}
3315   if (basisDerReal) {PetscValidPointer(basisDerReal, 4); *basisDerReal = prob->basisDerReal;}
3316   if (testReal)     {PetscValidPointer(testReal, 5);     *testReal     = prob->testReal;}
3317   if (testDerReal)  {PetscValidPointer(testDerReal, 6);  *testDerReal  = prob->testDerReal;}
3318   PetscFunctionReturn(0);
3319 }
3320 
3321 /*@C
3322   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 performed, using the kernels from PetscDSSetBdResidual().
3323 
3324   Collective on ds
3325 
3326   Input Parameters:
3327 + ds       - The PetscDS object
3328 . type     - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
3329 . name     - The BC name
3330 . label    - The label defining constrained points
3331 . Nv       - The number of DMLabel values for constrained points
3332 . values   - An array of label values for constrained points
3333 . field    - The field to constrain
3334 . Nc       - The number of constrained field components (0 will constrain all fields)
3335 . comps    - An array of constrained component numbers
3336 . bcFunc   - A pointwise function giving boundary values
3337 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3338 - ctx      - An optional user context for bcFunc
3339 
3340   Output Parameters:
3341 - bd       - The boundary number
3342 
3343   Options Database Keys:
3344 + -bc_<boundary name> <num> - Overrides the boundary ids
3345 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3346 
3347   Note:
3348   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
3349 
3350 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
3351 
3352   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
3353 
3354 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
3355 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
3356 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
3357 $        PetscReal time, const PetscReal x[], PetscScalar bcval[])
3358 
3359 + dim - the spatial dimension
3360 . Nf - the number of fields
3361 . uOff - the offset into u[] and u_t[] for each field
3362 . uOff_x - the offset into u_x[] for each field
3363 . u - each field evaluated at the current point
3364 . u_t - the time derivative of each field evaluated at the current point
3365 . u_x - the gradient of each field evaluated at the current point
3366 . aOff - the offset into a[] and a_t[] for each auxiliary field
3367 . aOff_x - the offset into a_x[] for each auxiliary field
3368 . a - each auxiliary field evaluated at the current point
3369 . a_t - the time derivative of each auxiliary field evaluated at the current point
3370 . a_x - the gradient of auxiliary each field evaluated at the current point
3371 . t - current time
3372 . x - coordinates of the current point
3373 . numConstants - number of constant parameters
3374 . constants - constant parameters
3375 - bcval - output values at the current point
3376 
3377   Level: developer
3378 
3379 .seealso: PetscDSAddBoundaryByName(), PetscDSGetBoundary(), PetscDSSetResidual(), PetscDSSetBdResidual()
3380 @*/
3381 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)
3382 {
3383   DSBoundary     head = ds->boundary, b;
3384   PetscInt       n    = 0;
3385   const char    *lname;
3386 
3387   PetscFunctionBegin;
3388   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3389   PetscValidLogicalCollectiveEnum(ds, type, 2);
3390   PetscValidCharPointer(name, 3);
3391   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
3392   PetscValidLogicalCollectiveInt(ds, Nv, 5);
3393   PetscValidLogicalCollectiveInt(ds, field, 7);
3394   PetscValidLogicalCollectiveInt(ds, Nc, 8);
3395   if (Nc > 0) {
3396     PetscInt *fcomps;
3397     PetscInt  c;
3398 
3399     PetscCall(PetscDSGetComponents(ds, &fcomps));
3400     PetscCheckFalse(Nc > fcomps[field],PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_OUTOFRANGE, "Number of constrained components %D > %D components for field %D", Nc, fcomps[field], field);
3401     for (c = 0; c < Nc; ++c) {
3402       PetscCheckFalse(comps[c] < 0 || comps[c] >= fcomps[field],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);
3403     }
3404   }
3405   PetscCall(PetscNew(&b));
3406   PetscCall(PetscStrallocpy(name, (char **) &b->name));
3407   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
3408   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
3409   PetscCall(PetscMalloc1(Nv, &b->values));
3410   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3411   PetscCall(PetscMalloc1(Nc, &b->comps));
3412   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3413   PetscCall(PetscObjectGetName((PetscObject) label, &lname));
3414   PetscCall(PetscStrallocpy(lname, (char **) &b->lname));
3415   b->type   = type;
3416   b->label  = label;
3417   b->Nv     = Nv;
3418   b->field  = field;
3419   b->Nc     = Nc;
3420   b->func   = bcFunc;
3421   b->func_t = bcFunc_t;
3422   b->ctx    = ctx;
3423   b->next   = NULL;
3424   /* Append to linked list so that we can preserve the order */
3425   if (!head) ds->boundary = b;
3426   while (head) {
3427     if (!head->next) {
3428       head->next = b;
3429       head       = b;
3430     }
3431     head = head->next;
3432     ++n;
3433   }
3434   if (bd) {PetscValidIntPointer(bd, 13); *bd = n;}
3435   PetscFunctionReturn(0);
3436 }
3437 
3438 /*@C
3439   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 performed, using the kernels from PetscDSSetBdResidual().
3440 
3441   Collective on ds
3442 
3443   Input Parameters:
3444 + ds       - The PetscDS object
3445 . type     - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
3446 . name     - The BC name
3447 . lname    - The naem of the label defining constrained points
3448 . Nv       - The number of DMLabel values for constrained points
3449 . values   - An array of label values for constrained points
3450 . field    - The field to constrain
3451 . Nc       - The number of constrained field components (0 will constrain all fields)
3452 . comps    - An array of constrained component numbers
3453 . bcFunc   - A pointwise function giving boundary values
3454 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3455 - ctx      - An optional user context for bcFunc
3456 
3457   Output Parameters:
3458 - bd       - The boundary number
3459 
3460   Options Database Keys:
3461 + -bc_<boundary name> <num> - Overrides the boundary ids
3462 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3463 
3464   Note:
3465   This function should only be used with DMForest currently, since labels cannot be defined before the underlygin Plex is built.
3466 
3467   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
3468 
3469 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
3470 
3471   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
3472 
3473 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
3474 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
3475 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
3476 $        PetscReal time, const PetscReal x[], PetscScalar bcval[])
3477 
3478 + dim - the spatial dimension
3479 . Nf - the number of fields
3480 . uOff - the offset into u[] and u_t[] for each field
3481 . uOff_x - the offset into u_x[] for each field
3482 . u - each field evaluated at the current point
3483 . u_t - the time derivative of each field evaluated at the current point
3484 . u_x - the gradient of each field evaluated at the current point
3485 . aOff - the offset into a[] and a_t[] for each auxiliary field
3486 . aOff_x - the offset into a_x[] for each auxiliary field
3487 . a - each auxiliary field evaluated at the current point
3488 . a_t - the time derivative of each auxiliary field evaluated at the current point
3489 . a_x - the gradient of auxiliary each field evaluated at the current point
3490 . t - current time
3491 . x - coordinates of the current point
3492 . numConstants - number of constant parameters
3493 . constants - constant parameters
3494 - bcval - output values at the current point
3495 
3496   Level: developer
3497 
3498 .seealso: PetscDSAddBoundary(), PetscDSGetBoundary(), PetscDSSetResidual(), PetscDSSetBdResidual()
3499 @*/
3500 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)
3501 {
3502   DSBoundary     head = ds->boundary, b;
3503   PetscInt       n    = 0;
3504 
3505   PetscFunctionBegin;
3506   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3507   PetscValidLogicalCollectiveEnum(ds, type, 2);
3508   PetscValidCharPointer(name, 3);
3509   PetscValidCharPointer(lname, 4);
3510   PetscValidLogicalCollectiveInt(ds, Nv, 5);
3511   PetscValidLogicalCollectiveInt(ds, field, 7);
3512   PetscValidLogicalCollectiveInt(ds, Nc, 8);
3513   PetscCall(PetscNew(&b));
3514   PetscCall(PetscStrallocpy(name, (char **) &b->name));
3515   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
3516   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
3517   PetscCall(PetscMalloc1(Nv, &b->values));
3518   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3519   PetscCall(PetscMalloc1(Nc, &b->comps));
3520   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3521   PetscCall(PetscStrallocpy(lname, (char **) &b->lname));
3522   b->type   = type;
3523   b->label  = NULL;
3524   b->Nv     = Nv;
3525   b->field  = field;
3526   b->Nc     = Nc;
3527   b->func   = bcFunc;
3528   b->func_t = bcFunc_t;
3529   b->ctx    = ctx;
3530   b->next   = NULL;
3531   /* Append to linked list so that we can preserve the order */
3532   if (!head) ds->boundary = b;
3533   while (head) {
3534     if (!head->next) {
3535       head->next = b;
3536       head       = b;
3537     }
3538     head = head->next;
3539     ++n;
3540   }
3541   if (bd) {PetscValidIntPointer(bd, 13); *bd = n;}
3542   PetscFunctionReturn(0);
3543 }
3544 
3545 /*@C
3546   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 performed, using the kernels from PetscDSSetBdResidual().
3547 
3548   Input Parameters:
3549 + ds       - The PetscDS object
3550 . bd       - The boundary condition number
3551 . type     - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
3552 . name     - The BC name
3553 . label    - The label defining constrained points
3554 . Nv       - The number of DMLabel ids for constrained points
3555 . values   - An array of ids for constrained points
3556 . field    - The field to constrain
3557 . Nc       - The number of constrained field components
3558 . comps    - An array of constrained component numbers
3559 . bcFunc   - A pointwise function giving boundary values
3560 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3561 - ctx      - An optional user context for bcFunc
3562 
3563   Note:
3564   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.
3565 
3566   Level: developer
3567 
3568 .seealso: PetscDSAddBoundary(), PetscDSGetBoundary(), PetscDSGetNumBoundary()
3569 @*/
3570 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)
3571 {
3572   DSBoundary     b = ds->boundary;
3573   PetscInt       n = 0;
3574 
3575   PetscFunctionBegin;
3576   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3577   while (b) {
3578     if (n == bd) break;
3579     b = b->next;
3580     ++n;
3581   }
3582   PetscCheck(b,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
3583   if (name) {
3584     PetscCall(PetscFree(b->name));
3585     PetscCall(PetscStrallocpy(name, (char **) &b->name));
3586   }
3587   b->type = type;
3588   if (label) {
3589     const char *name;
3590 
3591     b->label = label;
3592     PetscCall(PetscFree(b->lname));
3593     PetscCall(PetscObjectGetName((PetscObject) label, &name));
3594     PetscCall(PetscStrallocpy(name, (char **) &b->lname));
3595   }
3596   if (Nv >= 0) {
3597     b->Nv = Nv;
3598     PetscCall(PetscFree(b->values));
3599     PetscCall(PetscMalloc1(Nv, &b->values));
3600     if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3601   }
3602   if (field >= 0) b->field = field;
3603   if (Nc >= 0) {
3604     b->Nc = Nc;
3605     PetscCall(PetscFree(b->comps));
3606     PetscCall(PetscMalloc1(Nc, &b->comps));
3607     if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3608   }
3609   if (bcFunc)   b->func   = bcFunc;
3610   if (bcFunc_t) b->func_t = bcFunc_t;
3611   if (ctx)      b->ctx    = ctx;
3612   PetscFunctionReturn(0);
3613 }
3614 
3615 /*@
3616   PetscDSGetNumBoundary - Get the number of registered BC
3617 
3618   Input Parameters:
3619 . ds - The PetscDS object
3620 
3621   Output Parameters:
3622 . numBd - The number of BC
3623 
3624   Level: intermediate
3625 
3626 .seealso: PetscDSAddBoundary(), PetscDSGetBoundary()
3627 @*/
3628 PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
3629 {
3630   DSBoundary b = ds->boundary;
3631 
3632   PetscFunctionBegin;
3633   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3634   PetscValidIntPointer(numBd, 2);
3635   *numBd = 0;
3636   while (b) {++(*numBd); b = b->next;}
3637   PetscFunctionReturn(0);
3638 }
3639 
3640 /*@C
3641   PetscDSGetBoundary - Gets a boundary condition to the model
3642 
3643   Input Parameters:
3644 + ds          - The PetscDS object
3645 - bd          - The BC number
3646 
3647   Output Parameters:
3648 + wf       - The PetscWeakForm holding the pointwise functions
3649 . type     - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
3650 . name     - The BC name
3651 . label    - The label defining constrained points
3652 . Nv       - The number of DMLabel ids for constrained points
3653 . values   - An array of ids for constrained points
3654 . field    - The field to constrain
3655 . Nc       - The number of constrained field components
3656 . comps    - An array of constrained component numbers
3657 . bcFunc   - A pointwise function giving boundary values
3658 . bcFunc_t - A pointwise function giving the time derivative of the boundary values
3659 - ctx      - An optional user context for bcFunc
3660 
3661   Options Database Keys:
3662 + -bc_<boundary name> <num> - Overrides the boundary ids
3663 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3664 
3665   Level: developer
3666 
3667 .seealso: PetscDSAddBoundary()
3668 @*/
3669 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)
3670 {
3671   DSBoundary b = ds->boundary;
3672   PetscInt   n = 0;
3673 
3674   PetscFunctionBegin;
3675   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3676   while (b) {
3677     if (n == bd) break;
3678     b = b->next;
3679     ++n;
3680   }
3681   PetscCheck(b,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
3682   if (wf) {
3683     PetscValidPointer(wf, 3);
3684     *wf = b->wf;
3685   }
3686   if (type) {
3687     PetscValidPointer(type, 4);
3688     *type = b->type;
3689   }
3690   if (name) {
3691     PetscValidPointer(name, 5);
3692     *name = b->name;
3693   }
3694   if (label) {
3695     PetscValidPointer(label, 6);
3696     *label = b->label;
3697   }
3698   if (Nv) {
3699     PetscValidIntPointer(Nv, 7);
3700     *Nv = b->Nv;
3701   }
3702   if (values) {
3703     PetscValidPointer(values, 8);
3704     *values = b->values;
3705   }
3706   if (field) {
3707     PetscValidIntPointer(field, 9);
3708     *field = b->field;
3709   }
3710   if (Nc) {
3711     PetscValidIntPointer(Nc, 10);
3712     *Nc = b->Nc;
3713   }
3714   if (comps) {
3715     PetscValidPointer(comps, 11);
3716     *comps = b->comps;
3717   }
3718   if (func) {
3719     PetscValidPointer(func, 12);
3720     *func = b->func;
3721   }
3722   if (func_t) {
3723     PetscValidPointer(func_t, 13);
3724     *func_t = b->func_t;
3725   }
3726   if (ctx) {
3727     PetscValidPointer(ctx, 14);
3728     *ctx = b->ctx;
3729   }
3730   PetscFunctionReturn(0);
3731 }
3732 
3733 static PetscErrorCode DSBoundaryDuplicate_Internal(DSBoundary b, DSBoundary *bNew)
3734 {
3735   PetscFunctionBegin;
3736   PetscCall(PetscNew(bNew));
3737   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &(*bNew)->wf));
3738   PetscCall(PetscWeakFormCopy(b->wf, (*bNew)->wf));
3739   PetscCall(PetscStrallocpy(b->name,(char **) &((*bNew)->name)));
3740   PetscCall(PetscStrallocpy(b->lname,(char **) &((*bNew)->lname)));
3741   (*bNew)->type   = b->type;
3742   (*bNew)->label  = b->label;
3743   (*bNew)->Nv     = b->Nv;
3744   PetscCall(PetscMalloc1(b->Nv, &(*bNew)->values));
3745   PetscCall(PetscArraycpy((*bNew)->values, b->values, b->Nv));
3746   (*bNew)->field  = b->field;
3747   (*bNew)->Nc     = b->Nc;
3748   PetscCall(PetscMalloc1(b->Nc, &(*bNew)->comps));
3749   PetscCall(PetscArraycpy((*bNew)->comps, b->comps, b->Nc));
3750   (*bNew)->func   = b->func;
3751   (*bNew)->func_t = b->func_t;
3752   (*bNew)->ctx    = b->ctx;
3753   PetscFunctionReturn(0);
3754 }
3755 
3756 /*@
3757   PetscDSCopyBoundary - Copy all boundary condition objects to the new problem
3758 
3759   Not collective
3760 
3761   Input Parameters:
3762 + ds        - The source PetscDS object
3763 . numFields - The number of selected fields, or PETSC_DEFAULT for all fields
3764 - fields    - The selected fields, or NULL for all fields
3765 
3766   Output Parameter:
3767 . newds     - The target PetscDS, now with a copy of the boundary conditions
3768 
3769   Level: intermediate
3770 
3771 .seealso: PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3772 @*/
3773 PetscErrorCode PetscDSCopyBoundary(PetscDS ds, PetscInt numFields, const PetscInt fields[], PetscDS newds)
3774 {
3775   DSBoundary     b, *lastnext;
3776 
3777   PetscFunctionBegin;
3778   PetscValidHeaderSpecific(ds,    PETSCDS_CLASSID, 1);
3779   PetscValidHeaderSpecific(newds, PETSCDS_CLASSID, 4);
3780   if (ds == newds) PetscFunctionReturn(0);
3781   PetscCall(PetscDSDestroyBoundary(newds));
3782   lastnext = &(newds->boundary);
3783   for (b = ds->boundary; b; b = b->next) {
3784     DSBoundary bNew;
3785     PetscInt   fieldNew = -1;
3786 
3787     if (numFields > 0 && fields) {
3788       PetscInt f;
3789 
3790       for (f = 0; f < numFields; ++f) if (b->field == fields[f]) break;
3791       if (f == numFields) continue;
3792       fieldNew = f;
3793     }
3794     PetscCall(DSBoundaryDuplicate_Internal(b, &bNew));
3795     bNew->field = fieldNew < 0 ? b->field : fieldNew;
3796     *lastnext = bNew;
3797     lastnext  = &(bNew->next);
3798   }
3799   PetscFunctionReturn(0);
3800 }
3801 
3802 /*@
3803   PetscDSDestroyBoundary - Remove all DMBoundary objects from the PetscDS
3804 
3805   Not collective
3806 
3807   Input Parameter:
3808 . ds - The PetscDS object
3809 
3810   Level: intermediate
3811 
3812 .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations()
3813 @*/
3814 PetscErrorCode PetscDSDestroyBoundary(PetscDS ds)
3815 {
3816   DSBoundary     next = ds->boundary;
3817 
3818   PetscFunctionBegin;
3819   while (next) {
3820     DSBoundary b = next;
3821 
3822     next = b->next;
3823     PetscCall(PetscWeakFormDestroy(&b->wf));
3824     PetscCall(PetscFree(b->name));
3825     PetscCall(PetscFree(b->lname));
3826     PetscCall(PetscFree(b->values));
3827     PetscCall(PetscFree(b->comps));
3828     PetscCall(PetscFree(b));
3829   }
3830   PetscFunctionReturn(0);
3831 }
3832 
3833 /*@
3834   PetscDSSelectDiscretizations - Copy discretizations to the new problem with different field layout
3835 
3836   Not collective
3837 
3838   Input Parameters:
3839 + prob - The PetscDS object
3840 . numFields - Number of new fields
3841 - fields - Old field number for each new field
3842 
3843   Output Parameter:
3844 . newprob - The PetscDS copy
3845 
3846   Level: intermediate
3847 
3848 .seealso: PetscDSSelectEquations(), PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3849 @*/
3850 PetscErrorCode PetscDSSelectDiscretizations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
3851 {
3852   PetscInt       Nf, Nfn, fn;
3853 
3854   PetscFunctionBegin;
3855   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3856   if (fields) PetscValidIntPointer(fields, 3);
3857   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 4);
3858   PetscCall(PetscDSGetNumFields(prob, &Nf));
3859   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
3860   numFields = numFields < 0 ? Nf : numFields;
3861   for (fn = 0; fn < numFields; ++fn) {
3862     const PetscInt f = fields ? fields[fn] : fn;
3863     PetscObject    disc;
3864 
3865     if (f >= Nf) continue;
3866     PetscCall(PetscDSGetDiscretization(prob, f, &disc));
3867     PetscCall(PetscDSSetDiscretization(newprob, fn, disc));
3868   }
3869   PetscFunctionReturn(0);
3870 }
3871 
3872 /*@
3873   PetscDSSelectEquations - Copy pointwise function pointers to the new problem with different field layout
3874 
3875   Not collective
3876 
3877   Input Parameters:
3878 + prob - The PetscDS object
3879 . numFields - Number of new fields
3880 - fields - Old field number for each new field
3881 
3882   Output Parameter:
3883 . newprob - The PetscDS copy
3884 
3885   Level: intermediate
3886 
3887 .seealso: PetscDSSelectDiscretizations(), PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3888 @*/
3889 PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
3890 {
3891   PetscInt       Nf, Nfn, fn, gn;
3892 
3893   PetscFunctionBegin;
3894   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3895   if (fields) PetscValidIntPointer(fields, 3);
3896   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 4);
3897   PetscCall(PetscDSGetNumFields(prob, &Nf));
3898   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
3899   PetscCheckFalse(numFields > Nfn,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);
3900   for (fn = 0; fn < numFields; ++fn) {
3901     const PetscInt   f = fields ? fields[fn] : fn;
3902     PetscPointFunc   obj;
3903     PetscPointFunc   f0, f1;
3904     PetscBdPointFunc f0Bd, f1Bd;
3905     PetscRiemannFunc r;
3906 
3907     if (f >= Nf) continue;
3908     PetscCall(PetscDSGetObjective(prob, f, &obj));
3909     PetscCall(PetscDSGetResidual(prob, f, &f0, &f1));
3910     PetscCall(PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd));
3911     PetscCall(PetscDSGetRiemannSolver(prob, f, &r));
3912     PetscCall(PetscDSSetObjective(newprob, fn, obj));
3913     PetscCall(PetscDSSetResidual(newprob, fn, f0, f1));
3914     PetscCall(PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd));
3915     PetscCall(PetscDSSetRiemannSolver(newprob, fn, r));
3916     for (gn = 0; gn < numFields; ++gn) {
3917       const PetscInt  g = fields ? fields[gn] : gn;
3918       PetscPointJac   g0, g1, g2, g3;
3919       PetscPointJac   g0p, g1p, g2p, g3p;
3920       PetscBdPointJac g0Bd, g1Bd, g2Bd, g3Bd;
3921 
3922       if (g >= Nf) continue;
3923       PetscCall(PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3));
3924       PetscCall(PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p));
3925       PetscCall(PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd));
3926       PetscCall(PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3));
3927       PetscCall(PetscDSSetJacobianPreconditioner(newprob, fn, gn, g0p, g1p, g2p, g3p));
3928       PetscCall(PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd));
3929     }
3930   }
3931   PetscFunctionReturn(0);
3932 }
3933 
3934 /*@
3935   PetscDSCopyEquations - Copy all pointwise function pointers to the new problem
3936 
3937   Not collective
3938 
3939   Input Parameter:
3940 . prob - The PetscDS object
3941 
3942   Output Parameter:
3943 . newprob - The PetscDS copy
3944 
3945   Level: intermediate
3946 
3947 .seealso: PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3948 @*/
3949 PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
3950 {
3951   PetscWeakForm  wf, newwf;
3952   PetscInt       Nf, Ng;
3953 
3954   PetscFunctionBegin;
3955   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3956   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
3957   PetscCall(PetscDSGetNumFields(prob, &Nf));
3958   PetscCall(PetscDSGetNumFields(newprob, &Ng));
3959   PetscCheckFalse(Nf != Ng,PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %D != %D", Nf, Ng);
3960   PetscCall(PetscDSGetWeakForm(prob, &wf));
3961   PetscCall(PetscDSGetWeakForm(newprob, &newwf));
3962   PetscCall(PetscWeakFormCopy(wf, newwf));
3963   PetscFunctionReturn(0);
3964 }
3965 
3966 /*@
3967   PetscDSCopyConstants - Copy all constants to the new problem
3968 
3969   Not collective
3970 
3971   Input Parameter:
3972 . prob - The PetscDS object
3973 
3974   Output Parameter:
3975 . newprob - The PetscDS copy
3976 
3977   Level: intermediate
3978 
3979 .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3980 @*/
3981 PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
3982 {
3983   PetscInt           Nc;
3984   const PetscScalar *constants;
3985 
3986   PetscFunctionBegin;
3987   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3988   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
3989   PetscCall(PetscDSGetConstants(prob, &Nc, &constants));
3990   PetscCall(PetscDSSetConstants(newprob, Nc, (PetscScalar *) constants));
3991   PetscFunctionReturn(0);
3992 }
3993 
3994 /*@
3995   PetscDSCopyExactSolutions - Copy all exact solutions to the new problem
3996 
3997   Not collective
3998 
3999   Input Parameter:
4000 . ds - The PetscDS object
4001 
4002   Output Parameter:
4003 . newds - The PetscDS copy
4004 
4005   Level: intermediate
4006 
4007 .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
4008 @*/
4009 PetscErrorCode PetscDSCopyExactSolutions(PetscDS ds, PetscDS newds)
4010 {
4011   PetscSimplePointFunc sol;
4012   void                *ctx;
4013   PetscInt             Nf, f;
4014 
4015   PetscFunctionBegin;
4016   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4017   PetscValidHeaderSpecific(newds, PETSCDS_CLASSID, 2);
4018   PetscCall(PetscDSGetNumFields(ds, &Nf));
4019   for (f = 0; f < Nf; ++f) {
4020     PetscCall(PetscDSGetExactSolution(ds,    f, &sol, &ctx));
4021     PetscCall(PetscDSSetExactSolution(newds, f,  sol,  ctx));
4022     PetscCall(PetscDSGetExactSolutionTimeDerivative(ds,    f, &sol, &ctx));
4023     PetscCall(PetscDSSetExactSolutionTimeDerivative(newds, f,  sol,  ctx));
4024   }
4025   PetscFunctionReturn(0);
4026 }
4027 
4028 PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
4029 {
4030   PetscInt       dim, Nf, f;
4031 
4032   PetscFunctionBegin;
4033   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
4034   PetscValidPointer(subprob, 3);
4035   if (height == 0) {*subprob = prob; PetscFunctionReturn(0);}
4036   PetscCall(PetscDSGetNumFields(prob, &Nf));
4037   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
4038   PetscCheckFalse(height > dim,PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %D], not %D", dim, height);
4039   if (!prob->subprobs) PetscCall(PetscCalloc1(dim, &prob->subprobs));
4040   if (!prob->subprobs[height-1]) {
4041     PetscInt cdim;
4042 
4043     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject) prob), &prob->subprobs[height-1]));
4044     PetscCall(PetscDSGetCoordinateDimension(prob, &cdim));
4045     PetscCall(PetscDSSetCoordinateDimension(prob->subprobs[height-1], cdim));
4046     for (f = 0; f < Nf; ++f) {
4047       PetscFE      subfe;
4048       PetscObject  obj;
4049       PetscClassId id;
4050 
4051       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
4052       PetscCall(PetscObjectGetClassId(obj, &id));
4053       if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetHeightSubspace((PetscFE) obj, height, &subfe));
4054       else SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %d", f);
4055       PetscCall(PetscDSSetDiscretization(prob->subprobs[height-1], f, (PetscObject) subfe));
4056     }
4057   }
4058   *subprob = prob->subprobs[height-1];
4059   PetscFunctionReturn(0);
4060 }
4061 
4062 PetscErrorCode PetscDSGetDiscType_Internal(PetscDS ds, PetscInt f, PetscDiscType *disctype)
4063 {
4064   PetscObject    obj;
4065   PetscClassId   id;
4066   PetscInt       Nf;
4067 
4068   PetscFunctionBegin;
4069   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4070   PetscValidPointer(disctype, 3);
4071   *disctype = PETSC_DISC_NONE;
4072   PetscCall(PetscDSGetNumFields(ds, &Nf));
4073   PetscCheckFalse(f >= Nf,PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_SIZ, "Field %D must be in [0, %D)", f, Nf);
4074   PetscCall(PetscDSGetDiscretization(ds, f, &obj));
4075   if (obj) {
4076     PetscCall(PetscObjectGetClassId(obj, &id));
4077     if (id == PETSCFE_CLASSID) *disctype = PETSC_DISC_FE;
4078     else                       *disctype = PETSC_DISC_FV;
4079   }
4080   PetscFunctionReturn(0);
4081 }
4082 
4083 static PetscErrorCode PetscDSDestroy_Basic(PetscDS ds)
4084 {
4085   PetscFunctionBegin;
4086   PetscCall(PetscFree(ds->data));
4087   PetscFunctionReturn(0);
4088 }
4089 
4090 static PetscErrorCode PetscDSInitialize_Basic(PetscDS ds)
4091 {
4092   PetscFunctionBegin;
4093   ds->ops->setfromoptions = NULL;
4094   ds->ops->setup          = NULL;
4095   ds->ops->view           = NULL;
4096   ds->ops->destroy        = PetscDSDestroy_Basic;
4097   PetscFunctionReturn(0);
4098 }
4099 
4100 /*MC
4101   PETSCDSBASIC = "basic" - A discrete system with pointwise residual and boundary residual functions
4102 
4103   Level: intermediate
4104 
4105 .seealso: PetscDSType, PetscDSCreate(), PetscDSSetType()
4106 M*/
4107 
4108 PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS ds)
4109 {
4110   PetscDS_Basic *b;
4111 
4112   PetscFunctionBegin;
4113   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4114   PetscCall(PetscNewLog(ds, &b));
4115   ds->data = b;
4116 
4117   PetscCall(PetscDSInitialize_Basic(ds));
4118   PetscFunctionReturn(0);
4119 }
4120