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