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