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