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