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