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