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