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