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