xref: /petsc/src/dm/dt/interface/dtds.c (revision 12fc5b223091c94d5732fdf6b2ff0a471caa899e)
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
25 
26   Input Parameters:
27 + name        - The name of a new user-defined creation routine
28 - create_func - 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   Fortran Note:
51   Not available from Fortran
52 
53 .seealso: `PetscDSType`, `PetscDS`, `PetscDSRegisterAll()`, `PetscDSRegisterDestroy()`
54 @*/
55 PetscErrorCode PetscDSRegister(const char sname[], PetscErrorCode (*function)(PetscDS))
56 {
57   PetscFunctionBegin;
58   PetscCall(PetscFunctionListAdd(&PetscDSList, sname, function));
59   PetscFunctionReturn(PETSC_SUCCESS);
60 }
61 
62 /*@C
63   PetscDSSetType - Builds a particular `PetscDS`
64 
65   Collective on prob
66 
67   Input Parameters:
68 + prob - The `PetscDS` object
69 - name - The `PetscDSType`
70 
71   Options Database Key:
72 . -petscds_type <type> - Sets the PetscDS type; use -help for a list of available types
73 
74   Level: intermediate
75 
76   Fortran Note:
77   Not available from Fortran
78 
79 .seealso: `PetscDSType`, `PetscDS`, `PetscDSGetType()`, `PetscDSCreate()`
80 @*/
81 PetscErrorCode PetscDSSetType(PetscDS prob, PetscDSType name)
82 {
83   PetscErrorCode (*r)(PetscDS);
84   PetscBool match;
85 
86   PetscFunctionBegin;
87   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
88   PetscCall(PetscObjectTypeCompare((PetscObject)prob, name, &match));
89   if (match) PetscFunctionReturn(PETSC_SUCCESS);
90 
91   PetscCall(PetscDSRegisterAll());
92   PetscCall(PetscFunctionListFind(PetscDSList, name, &r));
93   PetscCheck(r, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDS type: %s", name);
94 
95   PetscTryTypeMethod(prob, destroy);
96   prob->ops->destroy = NULL;
97 
98   PetscCall((*r)(prob));
99   PetscCall(PetscObjectChangeTypeName((PetscObject)prob, name));
100   PetscFunctionReturn(PETSC_SUCCESS);
101 }
102 
103 /*@C
104   PetscDSGetType - Gets the `PetscDSType` name (as a string) from the `PetscDS`
105 
106   Not Collective
107 
108   Input Parameter:
109 . prob  - The `PetscDS`
110 
111   Output Parameter:
112 . name - The `PetscDSType` name
113 
114   Level: intermediate
115 
116   Fortran Note:
117   Not available from Fortran
118 
119 .seealso: `PetscDSType`, `PetscDS`, `PetscDSSetType()`, `PetscDSCreate()`
120 @*/
121 PetscErrorCode PetscDSGetType(PetscDS prob, PetscDSType *name)
122 {
123   PetscFunctionBegin;
124   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
125   PetscValidPointer(name, 2);
126   PetscCall(PetscDSRegisterAll());
127   *name = ((PetscObject)prob)->type_name;
128   PetscFunctionReturn(PETSC_SUCCESS);
129 }
130 
131 static PetscErrorCode PetscDSView_Ascii(PetscDS ds, PetscViewer viewer)
132 {
133   PetscViewerFormat  format;
134   const PetscScalar *constants;
135   PetscInt           Nf, numConstants, f;
136 
137   PetscFunctionBegin;
138   PetscCall(PetscDSGetNumFields(ds, &Nf));
139   PetscCall(PetscViewerGetFormat(viewer, &format));
140   PetscCall(PetscViewerASCIIPrintf(viewer, "Discrete System with %" PetscInt_FMT " fields\n", Nf));
141   PetscCall(PetscViewerASCIIPushTab(viewer));
142   PetscCall(PetscViewerASCIIPrintf(viewer, "  cell total dim %" PetscInt_FMT " total comp %" PetscInt_FMT "\n", ds->totDim, ds->totComp));
143   if (ds->isCohesive) PetscCall(PetscViewerASCIIPrintf(viewer, "  cohesive cell\n"));
144   for (f = 0; f < Nf; ++f) {
145     DSBoundary      b;
146     PetscObject     obj;
147     PetscClassId    id;
148     PetscQuadrature q;
149     const char     *name;
150     PetscInt        Nc, Nq, Nqc;
151 
152     PetscCall(PetscDSGetDiscretization(ds, f, &obj));
153     PetscCall(PetscObjectGetClassId(obj, &id));
154     PetscCall(PetscObjectGetName(obj, &name));
155     PetscCall(PetscViewerASCIIPrintf(viewer, "Field %s", name ? name : "<unknown>"));
156     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
157     if (id == PETSCFE_CLASSID) {
158       PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc));
159       PetscCall(PetscFEGetQuadrature((PetscFE)obj, &q));
160       PetscCall(PetscViewerASCIIPrintf(viewer, " FEM"));
161     } else if (id == PETSCFV_CLASSID) {
162       PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc));
163       PetscCall(PetscFVGetQuadrature((PetscFV)obj, &q));
164       PetscCall(PetscViewerASCIIPrintf(viewer, " FVM"));
165     } else SETERRQ(PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f);
166     if (Nc > 1) PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " components", Nc));
167     else PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT " component ", Nc));
168     if (ds->implicit[f]) PetscCall(PetscViewerASCIIPrintf(viewer, " (implicit)"));
169     else PetscCall(PetscViewerASCIIPrintf(viewer, " (explicit)"));
170     if (q) {
171       PetscCall(PetscQuadratureGetData(q, NULL, &Nqc, &Nq, NULL, NULL));
172       PetscCall(PetscViewerASCIIPrintf(viewer, " (Nq %" PetscInt_FMT " Nqc %" PetscInt_FMT ")", Nq, Nqc));
173     }
174     PetscCall(PetscViewerASCIIPrintf(viewer, " %" PetscInt_FMT "-jet", ds->jetDegree[f]));
175     PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
176     PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
177     PetscCall(PetscViewerASCIIPushTab(viewer));
178     if (id == PETSCFE_CLASSID) PetscCall(PetscFEView((PetscFE)obj, viewer));
179     else if (id == PETSCFV_CLASSID) PetscCall(PetscFVView((PetscFV)obj, viewer));
180     PetscCall(PetscViewerASCIIPopTab(viewer));
181 
182     for (b = ds->boundary; b; b = b->next) {
183       char    *name;
184       PetscInt c, i;
185 
186       if (b->field != f) continue;
187       PetscCall(PetscViewerASCIIPushTab(viewer));
188       PetscCall(PetscViewerASCIIPrintf(viewer, "Boundary %s (%s) %s\n", b->name, b->lname, DMBoundaryConditionTypes[b->type]));
189       if (!b->Nc) {
190         PetscCall(PetscViewerASCIIPrintf(viewer, "  all components\n"));
191       } else {
192         PetscCall(PetscViewerASCIIPrintf(viewer, "  components: "));
193         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
194         for (c = 0; c < b->Nc; ++c) {
195           if (c > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
196           PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT, b->comps[c]));
197         }
198         PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
199         PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
200       }
201       PetscCall(PetscViewerASCIIPrintf(viewer, "  values: "));
202       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_FALSE));
203       for (i = 0; i < b->Nv; ++i) {
204         if (i > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", "));
205         PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT, b->values[i]));
206       }
207       PetscCall(PetscViewerASCIIPrintf(viewer, "\n"));
208       PetscCall(PetscViewerASCIIUseTabs(viewer, PETSC_TRUE));
209 #if defined(__clang__)
210   #pragma clang diagnostic push
211   #pragma clang diagnostic ignored "-Wformat-pedantic"
212 #elif defined(__GNUC__) || defined(__GNUG__)
213   #pragma GCC diagnostic push
214   #pragma GCC diagnostic ignored "-Wformat"
215 #endif
216       if (b->func) {
217         PetscCall(PetscDLAddr(b->func, &name));
218         if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "  func: %s\n", name));
219         else PetscCall(PetscViewerASCIIPrintf(viewer, "  func: %p\n", b->func));
220         PetscCall(PetscFree(name));
221       }
222       if (b->func_t) {
223         PetscCall(PetscDLAddr(b->func_t, &name));
224         if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "  func_t: %s\n", name));
225         else PetscCall(PetscViewerASCIIPrintf(viewer, "  func_t: %p\n", b->func_t));
226         PetscCall(PetscFree(name));
227       }
228 #if defined(__clang__)
229   #pragma clang diagnostic pop
230 #elif defined(__GNUC__) || defined(__GNUG__)
231   #pragma GCC diagnostic pop
232 #endif
233       PetscCall(PetscWeakFormView(b->wf, viewer));
234       PetscCall(PetscViewerASCIIPopTab(viewer));
235     }
236   }
237   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
238   if (numConstants) {
239     PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT " constants\n", numConstants));
240     PetscCall(PetscViewerASCIIPushTab(viewer));
241     for (f = 0; f < numConstants; ++f) PetscCall(PetscViewerASCIIPrintf(viewer, "%g\n", (double)PetscRealPart(constants[f])));
242     PetscCall(PetscViewerASCIIPopTab(viewer));
243   }
244   PetscCall(PetscWeakFormView(ds->wf, viewer));
245   PetscCall(PetscViewerASCIIPopTab(viewer));
246   PetscFunctionReturn(PETSC_SUCCESS);
247 }
248 
249 /*@C
250    PetscDSViewFromOptions - View a `PetscDS` based on values in the options database
251 
252    Collective on PetscDS
253 
254    Input Parameters:
255 +  A - the `PetscDS` object
256 .  obj - Optional object
257 -  name - command line option
258 
259    Level: intermediate
260 
261 .seealso: `PetscDSType`, `PetscDS`, `PetscDSView()`, `PetscObjectViewFromOptions()`, `PetscDSCreate()`
262 @*/
263 PetscErrorCode PetscDSViewFromOptions(PetscDS A, PetscObject obj, const char name[])
264 {
265   PetscFunctionBegin;
266   PetscValidHeaderSpecific(A, PETSCDS_CLASSID, 1);
267   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
268   PetscFunctionReturn(PETSC_SUCCESS);
269 }
270 
271 /*@C
272   PetscDSView - Views a `PetscDS`
273 
274   Collective on prob
275 
276   Input Parameters:
277 + prob - the `PetscDS` object to view
278 - v  - the viewer
279 
280   Level: developer
281 
282 .seealso: `PetscDSType`, `PetscDS`, `PetscViewer`, `PetscDSDestroy()`
283 @*/
284 PetscErrorCode PetscDSView(PetscDS prob, PetscViewer v)
285 {
286   PetscBool iascii;
287 
288   PetscFunctionBegin;
289   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
290   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)prob), &v));
291   else PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
292   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
293   if (iascii) PetscCall(PetscDSView_Ascii(prob, v));
294   PetscTryTypeMethod(prob, view, v);
295   PetscFunctionReturn(PETSC_SUCCESS);
296 }
297 
298 /*@
299   PetscDSSetFromOptions - sets parameters in a `PetscDS` from the options database
300 
301   Collective on prob
302 
303   Input Parameter:
304 . prob - the `PetscDS` object to set options for
305 
306   Options Database Keys:
307 + -petscds_type <type>     - Set the `PetscDS` type
308 . -petscds_view <view opt> - View the `PetscDS`
309 . -petscds_jac_pre         - Turn formation of a separate Jacobian preconditioner on or off
310 . -bc_<name> <ids>         - Specify a list of label ids for a boundary condition
311 - -bc_<name>_comp <comps>  - Specify a list of field components to constrain for a boundary condition
312 
313   Level: intermediate
314 
315 .seealso: `PetscDS`, `PetscDSView()`
316 @*/
317 PetscErrorCode PetscDSSetFromOptions(PetscDS prob)
318 {
319   DSBoundary  b;
320   const char *defaultType;
321   char        name[256];
322   PetscBool   flg;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
326   if (!((PetscObject)prob)->type_name) {
327     defaultType = PETSCDSBASIC;
328   } else {
329     defaultType = ((PetscObject)prob)->type_name;
330   }
331   PetscCall(PetscDSRegisterAll());
332 
333   PetscObjectOptionsBegin((PetscObject)prob);
334   for (b = prob->boundary; b; b = b->next) {
335     char      optname[1024];
336     PetscInt  ids[1024], len = 1024;
337     PetscBool flg;
338 
339     PetscCall(PetscSNPrintf(optname, sizeof(optname), "-bc_%s", b->name));
340     PetscCall(PetscMemzero(ids, sizeof(ids)));
341     PetscCall(PetscOptionsIntArray(optname, "List of boundary IDs", "", ids, &len, &flg));
342     if (flg) {
343       b->Nv = len;
344       PetscCall(PetscFree(b->values));
345       PetscCall(PetscMalloc1(len, &b->values));
346       PetscCall(PetscArraycpy(b->values, ids, len));
347       PetscCall(PetscWeakFormRewriteKeys(b->wf, b->label, len, b->values));
348     }
349     len = 1024;
350     PetscCall(PetscSNPrintf(optname, sizeof(optname), "-bc_%s_comp", b->name));
351     PetscCall(PetscMemzero(ids, sizeof(ids)));
352     PetscCall(PetscOptionsIntArray(optname, "List of boundary field components", "", ids, &len, &flg));
353     if (flg) {
354       b->Nc = len;
355       PetscCall(PetscFree(b->comps));
356       PetscCall(PetscMalloc1(len, &b->comps));
357       PetscCall(PetscArraycpy(b->comps, ids, len));
358     }
359   }
360   PetscCall(PetscOptionsFList("-petscds_type", "Discrete System", "PetscDSSetType", PetscDSList, defaultType, name, 256, &flg));
361   if (flg) {
362     PetscCall(PetscDSSetType(prob, name));
363   } else if (!((PetscObject)prob)->type_name) {
364     PetscCall(PetscDSSetType(prob, defaultType));
365   }
366   PetscCall(PetscOptionsBool("-petscds_jac_pre", "Discrete System", "PetscDSUseJacobianPreconditioner", prob->useJacPre, &prob->useJacPre, &flg));
367   PetscCall(PetscOptionsBool("-petscds_force_quad", "Discrete System", "PetscDSSetForceQuad", prob->forceQuad, &prob->forceQuad, &flg));
368   PetscTryTypeMethod(prob, setfromoptions);
369   /* process any options handlers added with PetscObjectAddOptionsHandler() */
370   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)prob, PetscOptionsObject));
371   PetscOptionsEnd();
372   if (prob->Nf) PetscCall(PetscDSViewFromOptions(prob, NULL, "-petscds_view"));
373   PetscFunctionReturn(PETSC_SUCCESS);
374 }
375 
376 /*@C
377   PetscDSSetUp - Construct data structures for the `PetscDS`
378 
379   Collective on prob
380 
381   Input Parameter:
382 . prob - the `PetscDS` object to setup
383 
384   Level: developer
385 
386 .seealso: `PetscDS`, `PetscDSView()`, `PetscDSDestroy()`
387 @*/
388 PetscErrorCode PetscDSSetUp(PetscDS prob)
389 {
390   const PetscInt Nf   = prob->Nf;
391   PetscBool      hasH = PETSC_FALSE;
392   PetscInt       dim, dimEmbed, NbMax = 0, NcMax = 0, NqMax = 0, NsMax = 1, f;
393 
394   PetscFunctionBegin;
395   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
396   if (prob->setup) PetscFunctionReturn(PETSC_SUCCESS);
397   /* Calculate sizes */
398   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
399   PetscCall(PetscDSGetCoordinateDimension(prob, &dimEmbed));
400   prob->totDim = prob->totComp = 0;
401   PetscCall(PetscMalloc2(Nf, &prob->Nc, Nf, &prob->Nb));
402   PetscCall(PetscCalloc2(Nf + 1, &prob->off, Nf + 1, &prob->offDer));
403   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]));
404   PetscCall(PetscMalloc2(Nf, &prob->T, Nf, &prob->Tf));
405   if (prob->forceQuad) {
406     PetscQuadrature mq = NULL, mfq = NULL;
407     PetscInt        maxOrder = -1, maxFOrder = -1;
408 
409     for (f = 0; f < Nf; ++f) {
410       PetscObject     obj;
411       PetscClassId    id;
412       PetscQuadrature q = NULL, fq = NULL;
413       PetscInt        order = -1, forder = -1;
414 
415       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
416       if (!obj) continue;
417       PetscCall(PetscObjectGetClassId(obj, &id));
418       if (id == PETSCFE_CLASSID) {
419         PetscFE fe = (PetscFE)obj;
420 
421         PetscCall(PetscFEGetQuadrature(fe, &q));
422         PetscCall(PetscFEGetFaceQuadrature(fe, &fq));
423       } else if (id == PETSCFV_CLASSID) {
424         PetscFV fv = (PetscFV)obj;
425 
426         PetscCall(PetscFVGetQuadrature(fv, &q));
427       }
428       if (q) PetscCall(PetscQuadratureGetOrder(q, &order));
429       if (fq) PetscCall(PetscQuadratureGetOrder(fq, &forder));
430       if (order > maxOrder) {
431         maxOrder = order;
432         mq       = q;
433       }
434       if (forder > maxFOrder) {
435         maxFOrder = forder;
436         mfq       = fq;
437       }
438     }
439     for (f = 0; f < Nf; ++f) {
440       PetscObject  obj;
441       PetscClassId id;
442 
443       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
444       if (!obj) continue;
445       PetscCall(PetscObjectGetClassId(obj, &id));
446       if (id == PETSCFE_CLASSID) {
447         PetscFE fe = (PetscFE)obj;
448 
449         PetscCall(PetscFESetQuadrature(fe, mq));
450         PetscCall(PetscFESetFaceQuadrature(fe, mfq));
451       } else if (id == PETSCFV_CLASSID) {
452         PetscFV fv = (PetscFV)obj;
453 
454         PetscCall(PetscFVSetQuadrature(fv, mq));
455       }
456     }
457   }
458   for (f = 0; f < Nf; ++f) {
459     PetscObject     obj;
460     PetscClassId    id;
461     PetscQuadrature q  = NULL;
462     PetscInt        Nq = 0, Nb, Nc;
463 
464     PetscCall(PetscDSGetDiscretization(prob, f, &obj));
465     if (prob->jetDegree[f] > 1) hasH = PETSC_TRUE;
466     if (!obj) {
467       /* Empty mesh */
468       Nb = Nc    = 0;
469       prob->T[f] = prob->Tf[f] = NULL;
470     } else {
471       PetscCall(PetscObjectGetClassId(obj, &id));
472       if (id == PETSCFE_CLASSID) {
473         PetscFE fe = (PetscFE)obj;
474 
475         PetscCall(PetscFEGetQuadrature(fe, &q));
476         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 on prob
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 on prob
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   PetscValidIntPointer(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 for the callbacks f0 and f1:
1285 .vb
1286   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 for the callbacks f0 and f1:
1342 .vb
1343   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 for the callbacks f0 and f1:
1398 .vb
1399   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 for the callbacks g0, g1, g2 and g3:
1537 .vb
1538   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 for the callbacks g0, g1, g2 and g3:
1602 .vb
1603   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 for the callbacks g0, g1, g2 and g3:
1713 .vb
1714   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 for the callbacks g0, g1, g2 and g3:
1779 .vb
1780   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 for the callbacks g0, g1, g2 and g3:
1866 .vb
1867   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 for the callbacks g0, g1, g2 and g3:
1931 .vb
1932    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 for r:
1991 .vb
1992   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 for r:
2034 .vb
2035    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 for the callback update:
2075 .vb
2076   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 for the callback update:
2124 .vb
2125   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 for the callbacks f0 and f1:
2195 .vb
2196   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 for the callbacks f0 and f1:
2254 .vb
2255   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 for the callbacks g0, g1, g2 and g3:
2337 .vb
2338   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 for the callbacks g0, g1, g2 and g3:
2403 .vb
2404   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
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 for the callbacks g0, g1, g2 and g3:
2492 .vb
2493   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   Fortran Note:
2526   This is not yet available in Fortran.
2527 
2528 .seealso: `PetscDS`, `PetscDSSetBdJacobianPreconditioner()`
2529 @*/
2530 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[]))
2531 {
2532   PetscBdPointJac *tmp0, *tmp1, *tmp2, *tmp3;
2533   PetscInt         n0, n1, n2, n3;
2534 
2535   PetscFunctionBegin;
2536   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2537   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);
2538   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);
2539   PetscCall(PetscWeakFormGetBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, &n0, &tmp0, &n1, &tmp1, &n2, &tmp2, &n3, &tmp3));
2540   *g0 = tmp0 ? tmp0[0] : NULL;
2541   *g1 = tmp1 ? tmp1[0] : NULL;
2542   *g2 = tmp2 ? tmp2[0] : NULL;
2543   *g3 = tmp3 ? tmp3[0] : NULL;
2544   PetscFunctionReturn(PETSC_SUCCESS);
2545 }
2546 
2547 /*@C
2548   PetscDSSetBdJacobianPreconditioner - Set the pointwise boundary Jacobian preconditioner function for given test and basis field
2549 
2550   Not collective
2551 
2552   Input Parameters:
2553 + ds - The `PetscDS`
2554 . f  - The test field number
2555 . g  - The field number
2556 . g0 - integrand for the test and basis function term
2557 . g1 - integrand for the test function and basis function gradient term
2558 . g2 - integrand for the test function gradient and basis function term
2559 - g3 - integrand for the test function gradient and basis function gradient term
2560 
2561    Calling sequence for the callbacks g0, g1, g2 and g3:
2562 .vb
2563   g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2564      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2565      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2566      PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
2567 .ve
2568 + dim - the spatial dimension
2569 . Nf - the number of fields
2570 . NfAux - the number of auxiliary fields
2571 . uOff - the offset into u[] and u_t[] for each field
2572 . uOff_x - the offset into u_x[] for each field
2573 . u - each field evaluated at the current point
2574 . u_t - the time derivative of each field evaluated at the current point
2575 . u_x - the gradient of each field evaluated at the current point
2576 . aOff - the offset into a[] and a_t[] for each auxiliary field
2577 . aOff_x - the offset into a_x[] for each auxiliary field
2578 . a - each auxiliary field evaluated at the current point
2579 . a_t - the time derivative of each auxiliary field evaluated at the current point
2580 . a_x - the gradient of auxiliary each field evaluated at the current point
2581 . t - current time
2582 . u_tShift - the multiplier a for dF/dU_t
2583 . x - coordinates of the current point
2584 . n - normal at the current point
2585 . numConstants - number of constant parameters
2586 . constants - constant parameters
2587 - g0 - output values at the current point
2588 
2589   Level: intermediate
2590 
2591   Note:
2592   We are using a first order FEM model for the weak form:
2593   \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
2594 
2595   Fortran Note:
2596   This is not yet available in Fortran.
2597 
2598 .seealso: `PetscDS`, `PetscDSGetBdJacobianPreconditioner()`
2599 @*/
2600 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[]))
2601 {
2602   PetscFunctionBegin;
2603   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2604   if (g0) PetscValidFunction(g0, 4);
2605   if (g1) PetscValidFunction(g1, 5);
2606   if (g2) PetscValidFunction(g2, 6);
2607   if (g3) PetscValidFunction(g3, 7);
2608   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
2609   PetscCheck(g >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", g);
2610   PetscCall(PetscWeakFormSetIndexBdJacobianPreconditioner(ds->wf, NULL, 0, f, g, 0, 0, g0, 0, g1, 0, g2, 0, g3));
2611   PetscFunctionReturn(PETSC_SUCCESS);
2612 }
2613 
2614 /*@C
2615   PetscDSGetExactSolution - Get the pointwise exact solution function for a given test field
2616 
2617   Not collective
2618 
2619   Input Parameters:
2620 + prob - The PetscDS
2621 - f    - The test field number
2622 
2623   Output Parameters:
2624 + exactSol - exact solution for the test field
2625 - exactCtx - exact solution context
2626 
2627   Calling sequence for the solution functions:
2628 .vb
2629   sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2630 .ve
2631 + dim - the spatial dimension
2632 . t - current time
2633 . x - coordinates of the current point
2634 . Nc - the number of field components
2635 . u - the solution field evaluated at the current point
2636 - ctx - a user context
2637 
2638   Level: intermediate
2639 
2640 .seealso: `PetscDS`, `PetscDSSetExactSolution()`, `PetscDSGetExactSolutionTimeDerivative()`
2641 @*/
2642 PetscErrorCode PetscDSGetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
2643 {
2644   PetscFunctionBegin;
2645   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2646   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);
2647   if (sol) {
2648     PetscValidPointer(sol, 3);
2649     *sol = prob->exactSol[f];
2650   }
2651   if (ctx) {
2652     PetscValidPointer(ctx, 4);
2653     *ctx = prob->exactCtx[f];
2654   }
2655   PetscFunctionReturn(PETSC_SUCCESS);
2656 }
2657 
2658 /*@C
2659   PetscDSSetExactSolution - Set the pointwise exact solution function for a given test field
2660 
2661   Not collective
2662 
2663   Input Parameters:
2664 + prob - The `PetscDS`
2665 . f    - The test field number
2666 . sol  - solution function for the test fields
2667 - ctx  - solution context or NULL
2668 
2669   Calling sequence for solution functions:
2670 .vb
2671   sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2672 .ve
2673 + dim - the spatial dimension
2674 . t - current time
2675 . x - coordinates of the current point
2676 . Nc - the number of field components
2677 . u - the solution field evaluated at the current point
2678 - ctx - a user context
2679 
2680   Level: intermediate
2681 
2682 .seealso: `PetscDS`, `PetscDSGetExactSolution()`
2683 @*/
2684 PetscErrorCode PetscDSSetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
2685 {
2686   PetscFunctionBegin;
2687   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2688   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
2689   PetscCall(PetscDSEnlarge_Static(prob, f + 1));
2690   if (sol) {
2691     PetscValidFunction(sol, 3);
2692     prob->exactSol[f] = sol;
2693   }
2694   if (ctx) {
2695     PetscValidFunction(ctx, 4);
2696     prob->exactCtx[f] = ctx;
2697   }
2698   PetscFunctionReturn(PETSC_SUCCESS);
2699 }
2700 
2701 /*@C
2702   PetscDSGetExactSolutionTimeDerivative - Get the pointwise time derivative of the exact solution function for a given test field
2703 
2704   Not collective
2705 
2706   Input Parameters:
2707 + prob - The `PetscDS`
2708 - f    - The test field number
2709 
2710   Output Parameters:
2711 + exactSol - time derivative of the exact solution for the test field
2712 - exactCtx - time derivative of the exact solution context
2713 
2714   Calling sequence for the solution functions:
2715 .vb
2716   sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2717 .ve
2718 + dim - the spatial dimension
2719 . t - current time
2720 . x - coordinates of the current point
2721 . Nc - the number of field components
2722 . u - the solution field evaluated at the current point
2723 - ctx - a user context
2724 
2725   Level: intermediate
2726 
2727 .seealso: `PetscDS`, `PetscDSSetExactSolutionTimeDerivative()`, `PetscDSGetExactSolution()`
2728 @*/
2729 PetscErrorCode PetscDSGetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
2730 {
2731   PetscFunctionBegin;
2732   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2733   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);
2734   if (sol) {
2735     PetscValidPointer(sol, 3);
2736     *sol = prob->exactSol_t[f];
2737   }
2738   if (ctx) {
2739     PetscValidPointer(ctx, 4);
2740     *ctx = prob->exactCtx_t[f];
2741   }
2742   PetscFunctionReturn(PETSC_SUCCESS);
2743 }
2744 
2745 /*@C
2746   PetscDSSetExactSolutionTimeDerivative - Set the pointwise time derivative of the exact solution function for a given test field
2747 
2748   Not collective
2749 
2750   Input Parameters:
2751 + prob - The `PetscDS`
2752 . f    - The test field number
2753 . sol  - time derivative of the solution function for the test fields
2754 - ctx  - time derivative of the solution context or NULL
2755 
2756   Calling sequence for solution functions:
2757 .vb
2758   sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2759 .ve
2760 + dim - the spatial dimension
2761 . t - current time
2762 . x - coordinates of the current point
2763 . Nc - the number of field components
2764 . u - the solution field evaluated at the current point
2765 - ctx - a user context
2766 
2767   Level: intermediate
2768 
2769 .seealso: `PetscDS`, `PetscDSGetExactSolutionTimeDerivative()`, `PetscDSSetExactSolution()`
2770 @*/
2771 PetscErrorCode PetscDSSetExactSolutionTimeDerivative(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
2772 {
2773   PetscFunctionBegin;
2774   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2775   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
2776   PetscCall(PetscDSEnlarge_Static(prob, f + 1));
2777   if (sol) {
2778     PetscValidFunction(sol, 3);
2779     prob->exactSol_t[f] = sol;
2780   }
2781   if (ctx) {
2782     PetscValidFunction(ctx, 4);
2783     prob->exactCtx_t[f] = ctx;
2784   }
2785   PetscFunctionReturn(PETSC_SUCCESS);
2786 }
2787 
2788 /*@C
2789   PetscDSGetConstants - Returns the array of constants passed to point functions
2790 
2791   Not collective
2792 
2793   Input Parameter:
2794 . prob - The `PetscDS` object
2795 
2796   Output Parameters:
2797 + numConstants - The number of constants
2798 - constants    - The array of constants, NULL if there are none
2799 
2800   Level: intermediate
2801 
2802 .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSCreate()`
2803 @*/
2804 PetscErrorCode PetscDSGetConstants(PetscDS prob, PetscInt *numConstants, const PetscScalar *constants[])
2805 {
2806   PetscFunctionBegin;
2807   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2808   if (numConstants) {
2809     PetscValidIntPointer(numConstants, 2);
2810     *numConstants = prob->numConstants;
2811   }
2812   if (constants) {
2813     PetscValidPointer(constants, 3);
2814     *constants = prob->constants;
2815   }
2816   PetscFunctionReturn(PETSC_SUCCESS);
2817 }
2818 
2819 /*@C
2820   PetscDSSetConstants - Set the array of constants passed to point functions
2821 
2822   Not collective
2823 
2824   Input Parameters:
2825 + prob         - The `PetscDS` object
2826 . numConstants - The number of constants
2827 - constants    - The array of constants, NULL if there are none
2828 
2829   Level: intermediate
2830 
2831 .seealso: `PetscDS`, `PetscDSGetConstants()`, `PetscDSCreate()`
2832 @*/
2833 PetscErrorCode PetscDSSetConstants(PetscDS prob, PetscInt numConstants, PetscScalar constants[])
2834 {
2835   PetscFunctionBegin;
2836   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2837   if (numConstants != prob->numConstants) {
2838     PetscCall(PetscFree(prob->constants));
2839     prob->numConstants = numConstants;
2840     if (prob->numConstants) {
2841       PetscCall(PetscMalloc1(prob->numConstants, &prob->constants));
2842     } else {
2843       prob->constants = NULL;
2844     }
2845   }
2846   if (prob->numConstants) {
2847     PetscValidScalarPointer(constants, 3);
2848     PetscCall(PetscArraycpy(prob->constants, constants, prob->numConstants));
2849   }
2850   PetscFunctionReturn(PETSC_SUCCESS);
2851 }
2852 
2853 /*@
2854   PetscDSGetFieldIndex - Returns the index of the given field
2855 
2856   Not collective
2857 
2858   Input Parameters:
2859 + prob - The `PetscDS` object
2860 - disc - The discretization object
2861 
2862   Output Parameter:
2863 . f - The field number
2864 
2865   Level: beginner
2866 
2867 .seealso: `PetscDS`, `PetscGetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
2868 @*/
2869 PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
2870 {
2871   PetscInt g;
2872 
2873   PetscFunctionBegin;
2874   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2875   PetscValidIntPointer(f, 3);
2876   *f = -1;
2877   for (g = 0; g < prob->Nf; ++g) {
2878     if (disc == prob->disc[g]) break;
2879   }
2880   PetscCheck(g != prob->Nf, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
2881   *f = g;
2882   PetscFunctionReturn(PETSC_SUCCESS);
2883 }
2884 
2885 /*@
2886   PetscDSGetFieldSize - Returns the size of the given field in the full space basis
2887 
2888   Not collective
2889 
2890   Input Parameters:
2891 + prob - The `PetscDS` object
2892 - f - The field number
2893 
2894   Output Parameter:
2895 . size - The size
2896 
2897   Level: beginner
2898 
2899 .seealso: `PetscDS`, `PetscDSGetFieldOffset()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
2900 @*/
2901 PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
2902 {
2903   PetscFunctionBegin;
2904   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2905   PetscValidIntPointer(size, 3);
2906   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);
2907   PetscCall(PetscDSSetUp(prob));
2908   *size = prob->Nb[f];
2909   PetscFunctionReturn(PETSC_SUCCESS);
2910 }
2911 
2912 /*@
2913   PetscDSGetFieldOffset - Returns the offset of the given field in the full space basis
2914 
2915   Not collective
2916 
2917   Input Parameters:
2918 + prob - The `PetscDS` object
2919 - f - The field number
2920 
2921   Output Parameter:
2922 . off - The offset
2923 
2924   Level: beginner
2925 
2926 .seealso: `PetscDS`, `PetscDSGetFieldSize()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
2927 @*/
2928 PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
2929 {
2930   PetscInt size, g;
2931 
2932   PetscFunctionBegin;
2933   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2934   PetscValidIntPointer(off, 3);
2935   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);
2936   *off = 0;
2937   for (g = 0; g < f; ++g) {
2938     PetscCall(PetscDSGetFieldSize(prob, g, &size));
2939     *off += size;
2940   }
2941   PetscFunctionReturn(PETSC_SUCCESS);
2942 }
2943 
2944 /*@
2945   PetscDSGetFieldOffsetCohesive - Returns the offset of the given field in the full space basis on a cohesive cell
2946 
2947   Not collective
2948 
2949   Input Parameters:
2950 + prob - The `PetscDS` object
2951 - f - The field number
2952 
2953   Output Parameter:
2954 . off - The offset
2955 
2956   Level: beginner
2957 
2958 .seealso: `PetscDS`, `PetscDSGetFieldSize()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
2959 @*/
2960 PetscErrorCode PetscDSGetFieldOffsetCohesive(PetscDS ds, PetscInt f, PetscInt *off)
2961 {
2962   PetscInt size, g;
2963 
2964   PetscFunctionBegin;
2965   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2966   PetscValidIntPointer(off, 3);
2967   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);
2968   *off = 0;
2969   for (g = 0; g < f; ++g) {
2970     PetscBool cohesive;
2971 
2972     PetscCall(PetscDSGetCohesive(ds, g, &cohesive));
2973     PetscCall(PetscDSGetFieldSize(ds, g, &size));
2974     *off += cohesive ? size : size * 2;
2975   }
2976   PetscFunctionReturn(PETSC_SUCCESS);
2977 }
2978 
2979 /*@
2980   PetscDSGetDimensions - Returns the size of the approximation space for each field on an evaluation point
2981 
2982   Not collective
2983 
2984   Input Parameter:
2985 . prob - The `PetscDS` object
2986 
2987   Output Parameter:
2988 . dimensions - The number of dimensions
2989 
2990   Level: beginner
2991 
2992 .seealso: `PetscDS`, `PetscDSGetComponentOffsets()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
2993 @*/
2994 PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
2995 {
2996   PetscFunctionBegin;
2997   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2998   PetscCall(PetscDSSetUp(prob));
2999   PetscValidPointer(dimensions, 2);
3000   *dimensions = prob->Nb;
3001   PetscFunctionReturn(PETSC_SUCCESS);
3002 }
3003 
3004 /*@
3005   PetscDSGetComponents - Returns the number of components for each field on an evaluation point
3006 
3007   Not collective
3008 
3009   Input Parameter:
3010 . prob - The `PetscDS` object
3011 
3012   Output Parameter:
3013 . components - The number of components
3014 
3015   Level: beginner
3016 
3017 .seealso: `PetscDS`, `PetscDSGetComponentOffsets()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3018 @*/
3019 PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
3020 {
3021   PetscFunctionBegin;
3022   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3023   PetscCall(PetscDSSetUp(prob));
3024   PetscValidPointer(components, 2);
3025   *components = prob->Nc;
3026   PetscFunctionReturn(PETSC_SUCCESS);
3027 }
3028 
3029 /*@
3030   PetscDSGetComponentOffset - Returns the offset of the given field on an evaluation point
3031 
3032   Not collective
3033 
3034   Input Parameters:
3035 + prob - The `PetscDS` object
3036 - f - The field number
3037 
3038   Output Parameter:
3039 . off - The offset
3040 
3041   Level: beginner
3042 
3043 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3044 @*/
3045 PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
3046 {
3047   PetscFunctionBegin;
3048   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3049   PetscValidIntPointer(off, 3);
3050   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);
3051   PetscCall(PetscDSSetUp(prob));
3052   *off = prob->off[f];
3053   PetscFunctionReturn(PETSC_SUCCESS);
3054 }
3055 
3056 /*@
3057   PetscDSGetComponentOffsets - Returns the offset of each field on an evaluation point
3058 
3059   Not collective
3060 
3061   Input Parameter:
3062 . prob - The `PetscDS` object
3063 
3064   Output Parameter:
3065 . offsets - The offsets
3066 
3067   Level: beginner
3068 
3069 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3070 @*/
3071 PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
3072 {
3073   PetscFunctionBegin;
3074   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3075   PetscValidPointer(offsets, 2);
3076   PetscCall(PetscDSSetUp(prob));
3077   *offsets = prob->off;
3078   PetscFunctionReturn(PETSC_SUCCESS);
3079 }
3080 
3081 /*@
3082   PetscDSGetComponentDerivativeOffsets - Returns the offset of each field derivative on an evaluation point
3083 
3084   Not collective
3085 
3086   Input Parameter:
3087 . prob - The `PetscDS` object
3088 
3089   Output Parameter:
3090 . offsets - The offsets
3091 
3092   Level: beginner
3093 
3094 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3095 @*/
3096 PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
3097 {
3098   PetscFunctionBegin;
3099   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3100   PetscValidPointer(offsets, 2);
3101   PetscCall(PetscDSSetUp(prob));
3102   *offsets = prob->offDer;
3103   PetscFunctionReturn(PETSC_SUCCESS);
3104 }
3105 
3106 /*@
3107   PetscDSGetComponentOffsetsCohesive - Returns the offset of each field on an evaluation point
3108 
3109   Not collective
3110 
3111   Input Parameters:
3112 + ds - The `PetscDS` object
3113 - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive
3114 
3115   Output Parameter:
3116 . offsets - The offsets
3117 
3118   Level: beginner
3119 
3120 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3121 @*/
3122 PetscErrorCode PetscDSGetComponentOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
3123 {
3124   PetscFunctionBegin;
3125   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3126   PetscValidPointer(offsets, 3);
3127   PetscCheck(ds->isCohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
3128   PetscCheck(!(s < 0) && !(s > 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %" PetscInt_FMT " is not in [0, 2]", s);
3129   PetscCall(PetscDSSetUp(ds));
3130   *offsets = ds->offCohesive[s];
3131   PetscFunctionReturn(PETSC_SUCCESS);
3132 }
3133 
3134 /*@
3135   PetscDSGetComponentDerivativeOffsetsCohesive - Returns the offset of each field derivative on an evaluation point
3136 
3137   Not collective
3138 
3139   Input Parameters:
3140 + ds - The `PetscDS` object
3141 - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive
3142 
3143   Output Parameter:
3144 . offsets - The offsets
3145 
3146   Level: beginner
3147 
3148 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3149 @*/
3150 PetscErrorCode PetscDSGetComponentDerivativeOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
3151 {
3152   PetscFunctionBegin;
3153   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3154   PetscValidPointer(offsets, 3);
3155   PetscCheck(ds->isCohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
3156   PetscCheck(!(s < 0) && !(s > 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %" PetscInt_FMT " is not in [0, 2]", s);
3157   PetscCall(PetscDSSetUp(ds));
3158   *offsets = ds->offDerCohesive[s];
3159   PetscFunctionReturn(PETSC_SUCCESS);
3160 }
3161 
3162 /*@C
3163   PetscDSGetTabulation - Return the basis tabulation at quadrature points for the volume discretization
3164 
3165   Not collective
3166 
3167   Input Parameter:
3168 . prob - The `PetscDS` object
3169 
3170   Output Parameter:
3171 . T - The basis function and derivatives tabulation at quadrature points for each field
3172 
3173   Level: intermediate
3174 
3175 .seealso: `PetscDS`, `PetscTabulation`, `PetscDSCreate()`
3176 @*/
3177 PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[])
3178 {
3179   PetscFunctionBegin;
3180   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3181   PetscValidPointer(T, 2);
3182   PetscCall(PetscDSSetUp(prob));
3183   *T = prob->T;
3184   PetscFunctionReturn(PETSC_SUCCESS);
3185 }
3186 
3187 /*@C
3188   PetscDSGetFaceTabulation - Return the basis tabulation at quadrature points on the faces
3189 
3190   Not collective
3191 
3192   Input Parameter:
3193 . prob - The `PetscDS` object
3194 
3195   Output Parameter:
3196 . Tf - The basis function and derivative tabulation on each local face at quadrature points for each and field
3197 
3198   Level: intermediate
3199 
3200 .seealso: `PetscTabulation`, `PetscDS`, `PetscDSGetTabulation()`, `PetscDSCreate()`
3201 @*/
3202 PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
3203 {
3204   PetscFunctionBegin;
3205   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3206   PetscValidPointer(Tf, 2);
3207   PetscCall(PetscDSSetUp(prob));
3208   *Tf = prob->Tf;
3209   PetscFunctionReturn(PETSC_SUCCESS);
3210 }
3211 
3212 PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
3213 {
3214   PetscFunctionBegin;
3215   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3216   PetscCall(PetscDSSetUp(prob));
3217   if (u) {
3218     PetscValidPointer(u, 2);
3219     *u = prob->u;
3220   }
3221   if (u_t) {
3222     PetscValidPointer(u_t, 3);
3223     *u_t = prob->u_t;
3224   }
3225   if (u_x) {
3226     PetscValidPointer(u_x, 4);
3227     *u_x = prob->u_x;
3228   }
3229   PetscFunctionReturn(PETSC_SUCCESS);
3230 }
3231 
3232 PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar **f0, PetscScalar **f1, PetscScalar **g0, PetscScalar **g1, PetscScalar **g2, PetscScalar **g3)
3233 {
3234   PetscFunctionBegin;
3235   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3236   PetscCall(PetscDSSetUp(prob));
3237   if (f0) {
3238     PetscValidPointer(f0, 2);
3239     *f0 = prob->f0;
3240   }
3241   if (f1) {
3242     PetscValidPointer(f1, 3);
3243     *f1 = prob->f1;
3244   }
3245   if (g0) {
3246     PetscValidPointer(g0, 4);
3247     *g0 = prob->g0;
3248   }
3249   if (g1) {
3250     PetscValidPointer(g1, 5);
3251     *g1 = prob->g1;
3252   }
3253   if (g2) {
3254     PetscValidPointer(g2, 6);
3255     *g2 = prob->g2;
3256   }
3257   if (g3) {
3258     PetscValidPointer(g3, 7);
3259     *g3 = prob->g3;
3260   }
3261   PetscFunctionReturn(PETSC_SUCCESS);
3262 }
3263 
3264 PetscErrorCode PetscDSGetWorkspace(PetscDS prob, PetscReal **x, PetscScalar **basisReal, PetscScalar **basisDerReal, PetscScalar **testReal, PetscScalar **testDerReal)
3265 {
3266   PetscFunctionBegin;
3267   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3268   PetscCall(PetscDSSetUp(prob));
3269   if (x) {
3270     PetscValidPointer(x, 2);
3271     *x = prob->x;
3272   }
3273   if (basisReal) {
3274     PetscValidPointer(basisReal, 3);
3275     *basisReal = prob->basisReal;
3276   }
3277   if (basisDerReal) {
3278     PetscValidPointer(basisDerReal, 4);
3279     *basisDerReal = prob->basisDerReal;
3280   }
3281   if (testReal) {
3282     PetscValidPointer(testReal, 5);
3283     *testReal = prob->testReal;
3284   }
3285   if (testDerReal) {
3286     PetscValidPointer(testDerReal, 6);
3287     *testDerReal = prob->testDerReal;
3288   }
3289   PetscFunctionReturn(PETSC_SUCCESS);
3290 }
3291 
3292 /*@C
3293   PetscDSAddBoundary - Add a boundary condition to the model. The pointwise functions are used to provide boundary values for essential boundary conditions.
3294   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
3295   integrals should be performed, using the kernels from `PetscDSSetBdResidual()`.
3296 
3297   Collective on ds
3298 
3299   Input Parameters:
3300 + ds       - The PetscDS object
3301 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
3302 . name     - The BC name
3303 . label    - The label defining constrained points
3304 . Nv       - The number of `DMLabel` values for constrained points
3305 . values   - An array of label values for constrained points
3306 . field    - The field to constrain
3307 . Nc       - The number of constrained field components (0 will constrain all fields)
3308 . comps    - An array of constrained component numbers
3309 . bcFunc   - A pointwise function giving boundary values
3310 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3311 - ctx      - An optional user context for bcFunc
3312 
3313   Output Parameters:
3314 - bd       - The boundary number
3315 
3316   Options Database Keys:
3317 + -bc_<boundary name> <num> - Overrides the boundary ids
3318 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3319 
3320   Level: developer
3321 
3322   Note:
3323   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, Then the calling sequence is:
3324 
3325 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
3326 
3327   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is:
3328 .vb
3329   bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
3330          const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
3331          const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
3332          PetscReal time, const PetscReal x[], PetscScalar bcval[])
3333 .ve
3334 + dim - the spatial dimension
3335 . Nf - the number of fields
3336 . uOff - the offset into u[] and u_t[] for each field
3337 . uOff_x - the offset into u_x[] for each field
3338 . u - each field evaluated at the current point
3339 . u_t - the time derivative of each field evaluated at the current point
3340 . u_x - the gradient of each field evaluated at the current point
3341 . aOff - the offset into a[] and a_t[] for each auxiliary field
3342 . aOff_x - the offset into a_x[] for each auxiliary field
3343 . a - each auxiliary field evaluated at the current point
3344 . a_t - the time derivative of each auxiliary field evaluated at the current point
3345 . a_x - the gradient of auxiliary each field evaluated at the current point
3346 . t - current time
3347 . x - coordinates of the current point
3348 . numConstants - number of constant parameters
3349 . constants - constant parameters
3350 - bcval - output values at the current point
3351 
3352 .seealso: `PetscDS`, `PetscWeakForm`, `DMLabel`, `DMBoundaryConditionType`, `PetscDSAddBoundaryByName()`, `PetscDSGetBoundary()`, `PetscDSSetResidual()`, `PetscDSSetBdResidual()`
3353 @*/
3354 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)
3355 {
3356   DSBoundary  head = ds->boundary, b;
3357   PetscInt    n    = 0;
3358   const char *lname;
3359 
3360   PetscFunctionBegin;
3361   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3362   PetscValidLogicalCollectiveEnum(ds, type, 2);
3363   PetscValidCharPointer(name, 3);
3364   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
3365   PetscValidLogicalCollectiveInt(ds, Nv, 5);
3366   PetscValidLogicalCollectiveInt(ds, field, 7);
3367   PetscValidLogicalCollectiveInt(ds, Nc, 8);
3368   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);
3369   if (Nc > 0) {
3370     PetscInt *fcomps;
3371     PetscInt  c;
3372 
3373     PetscCall(PetscDSGetComponents(ds, &fcomps));
3374     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);
3375     for (c = 0; c < Nc; ++c) {
3376       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);
3377     }
3378   }
3379   PetscCall(PetscNew(&b));
3380   PetscCall(PetscStrallocpy(name, (char **)&b->name));
3381   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
3382   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
3383   PetscCall(PetscMalloc1(Nv, &b->values));
3384   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3385   PetscCall(PetscMalloc1(Nc, &b->comps));
3386   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3387   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
3388   PetscCall(PetscStrallocpy(lname, (char **)&b->lname));
3389   b->type   = type;
3390   b->label  = label;
3391   b->Nv     = Nv;
3392   b->field  = field;
3393   b->Nc     = Nc;
3394   b->func   = bcFunc;
3395   b->func_t = bcFunc_t;
3396   b->ctx    = ctx;
3397   b->next   = NULL;
3398   /* Append to linked list so that we can preserve the order */
3399   if (!head) ds->boundary = b;
3400   while (head) {
3401     if (!head->next) {
3402       head->next = b;
3403       head       = b;
3404     }
3405     head = head->next;
3406     ++n;
3407   }
3408   if (bd) {
3409     PetscValidIntPointer(bd, 13);
3410     *bd = n;
3411   }
3412   PetscFunctionReturn(PETSC_SUCCESS);
3413 }
3414 
3415 /*@C
3416   PetscDSAddBoundaryByName - Add a boundary condition to the model. The pointwise functions are used to provide boundary values for essential boundary conditions.
3417   In FEM, they are acting upon by dual basis functionals to generate FEM coefficients which are fixed. Natural boundary conditions signal to PETSc that
3418   boundary integrals should be performed, using the kernels from `PetscDSSetBdResidual()`.
3419 
3420   Collective on ds
3421 
3422   Input Parameters:
3423 + ds       - The `PetscDS` object
3424 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
3425 . name     - The BC name
3426 . lname    - The naem of the label defining constrained points
3427 . Nv       - The number of `DMLabel` values for constrained points
3428 . values   - An array of label values for constrained points
3429 . field    - The field to constrain
3430 . Nc       - The number of constrained field components (0 will constrain all fields)
3431 . comps    - An array of constrained component numbers
3432 . bcFunc   - A pointwise function giving boundary values
3433 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3434 - ctx      - An optional user context for bcFunc
3435 
3436   Output Parameters:
3437 - bd       - The boundary number
3438 
3439   Options Database Keys:
3440 + -bc_<boundary name> <num> - Overrides the boundary ids
3441 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3442 
3443   Calling Sequence of bcFunc() and bcFunc_t():
3444   If the type is `DM_BC_ESSENTIAL`
3445 .vb
3446   bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
3447 .ve
3448   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value,
3449 .vb
3450   bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
3451          const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
3452          const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
3453          PetscReal time, const PetscReal x[], PetscScalar bcval[])
3454 .ve
3455 + dim - the spatial dimension
3456 . Nf - the number of fields
3457 . uOff - the offset into u[] and u_t[] for each field
3458 . uOff_x - the offset into u_x[] for each field
3459 . u - each field evaluated at the current point
3460 . u_t - the time derivative of each field evaluated at the current point
3461 . u_x - the gradient of each field evaluated at the current point
3462 . aOff - the offset into a[] and a_t[] for each auxiliary field
3463 . aOff_x - the offset into a_x[] for each auxiliary field
3464 . a - each auxiliary field evaluated at the current point
3465 . a_t - the time derivative of each auxiliary field evaluated at the current point
3466 . a_x - the gradient of auxiliary each field evaluated at the current point
3467 . t - current time
3468 . x - coordinates of the current point
3469 . numConstants - number of constant parameters
3470 . constants - constant parameters
3471 - bcval - output values at the current point
3472 
3473   Level: developer
3474 
3475   Note:
3476   This function should only be used with `DMFOREST` currently, since labels cannot be defined before the underlying `DMPLEX` is built.
3477 
3478 .seealso: `PetscDS`, `PetscWeakForm`, `DMLabel`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`, `PetscDSSetResidual()`, `PetscDSSetBdResidual()`
3479 @*/
3480 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)
3481 {
3482   DSBoundary head = ds->boundary, b;
3483   PetscInt   n    = 0;
3484 
3485   PetscFunctionBegin;
3486   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3487   PetscValidLogicalCollectiveEnum(ds, type, 2);
3488   PetscValidCharPointer(name, 3);
3489   PetscValidCharPointer(lname, 4);
3490   PetscValidLogicalCollectiveInt(ds, Nv, 5);
3491   PetscValidLogicalCollectiveInt(ds, field, 7);
3492   PetscValidLogicalCollectiveInt(ds, Nc, 8);
3493   PetscCall(PetscNew(&b));
3494   PetscCall(PetscStrallocpy(name, (char **)&b->name));
3495   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
3496   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
3497   PetscCall(PetscMalloc1(Nv, &b->values));
3498   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3499   PetscCall(PetscMalloc1(Nc, &b->comps));
3500   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3501   PetscCall(PetscStrallocpy(lname, (char **)&b->lname));
3502   b->type   = type;
3503   b->label  = NULL;
3504   b->Nv     = Nv;
3505   b->field  = field;
3506   b->Nc     = Nc;
3507   b->func   = bcFunc;
3508   b->func_t = bcFunc_t;
3509   b->ctx    = ctx;
3510   b->next   = NULL;
3511   /* Append to linked list so that we can preserve the order */
3512   if (!head) ds->boundary = b;
3513   while (head) {
3514     if (!head->next) {
3515       head->next = b;
3516       head       = b;
3517     }
3518     head = head->next;
3519     ++n;
3520   }
3521   if (bd) {
3522     PetscValidIntPointer(bd, 13);
3523     *bd = n;
3524   }
3525   PetscFunctionReturn(PETSC_SUCCESS);
3526 }
3527 
3528 /*@C
3529   PetscDSUpdateBoundary - Change a boundary condition for the model. The pointwise functions are used to provide boundary values for essential boundary conditions.
3530   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
3531   should be performed, using the kernels from `PetscDSSetBdResidual()`.
3532 
3533   Input Parameters:
3534 + ds       - The `PetscDS` object
3535 . bd       - The boundary condition number
3536 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
3537 . name     - The BC name
3538 . label    - The label defining constrained points
3539 . Nv       - The number of `DMLabel` ids for constrained points
3540 . values   - An array of ids for constrained points
3541 . field    - The field to constrain
3542 . Nc       - The number of constrained field components
3543 . comps    - An array of constrained component numbers
3544 . bcFunc   - A pointwise function giving boundary values
3545 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3546 - ctx      - An optional user context for bcFunc
3547 
3548   Level: developer
3549 
3550   Note:
3551   The boundary condition number is the order in which it was registered. The user can get the number of boundary conditions from `PetscDSGetNumBoundary()`.
3552   See `PetscDSAddBoundary()` for a description of the calling sequences for the callbacks.
3553 
3554 .seealso: `PetscDS`, `PetscWeakForm`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`, `PetscDSGetNumBoundary()`, `DMLabel`
3555 @*/
3556 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)
3557 {
3558   DSBoundary b = ds->boundary;
3559   PetscInt   n = 0;
3560 
3561   PetscFunctionBegin;
3562   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3563   while (b) {
3564     if (n == bd) break;
3565     b = b->next;
3566     ++n;
3567   }
3568   PetscCheck(b, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bd, n);
3569   if (name) {
3570     PetscCall(PetscFree(b->name));
3571     PetscCall(PetscStrallocpy(name, (char **)&b->name));
3572   }
3573   b->type = type;
3574   if (label) {
3575     const char *name;
3576 
3577     b->label = label;
3578     PetscCall(PetscFree(b->lname));
3579     PetscCall(PetscObjectGetName((PetscObject)label, &name));
3580     PetscCall(PetscStrallocpy(name, (char **)&b->lname));
3581   }
3582   if (Nv >= 0) {
3583     b->Nv = Nv;
3584     PetscCall(PetscFree(b->values));
3585     PetscCall(PetscMalloc1(Nv, &b->values));
3586     if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3587   }
3588   if (field >= 0) b->field = field;
3589   if (Nc >= 0) {
3590     b->Nc = Nc;
3591     PetscCall(PetscFree(b->comps));
3592     PetscCall(PetscMalloc1(Nc, &b->comps));
3593     if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3594   }
3595   if (bcFunc) b->func = bcFunc;
3596   if (bcFunc_t) b->func_t = bcFunc_t;
3597   if (ctx) b->ctx = ctx;
3598   PetscFunctionReturn(PETSC_SUCCESS);
3599 }
3600 
3601 /*@
3602   PetscDSGetNumBoundary - Get the number of registered BC
3603 
3604   Input Parameters:
3605 . ds - The `PetscDS` object
3606 
3607   Output Parameters:
3608 . numBd - The number of BC
3609 
3610   Level: intermediate
3611 
3612 .seealso: `PetscDS`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`
3613 @*/
3614 PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
3615 {
3616   DSBoundary b = ds->boundary;
3617 
3618   PetscFunctionBegin;
3619   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3620   PetscValidIntPointer(numBd, 2);
3621   *numBd = 0;
3622   while (b) {
3623     ++(*numBd);
3624     b = b->next;
3625   }
3626   PetscFunctionReturn(PETSC_SUCCESS);
3627 }
3628 
3629 /*@C
3630   PetscDSGetBoundary - Gets a boundary condition to the model
3631 
3632   Input Parameters:
3633 + ds          - The `PetscDS` object
3634 - bd          - The BC number
3635 
3636   Output Parameters:
3637 + wf       - The `PetscWeakForm` holding the pointwise functions
3638 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
3639 . name     - The BC name
3640 . label    - The label defining constrained points
3641 . Nv       - The number of `DMLabel` ids for constrained points
3642 . values   - An array of ids for constrained points
3643 . field    - The field to constrain
3644 . Nc       - The number of constrained field components
3645 . comps    - An array of constrained component numbers
3646 . bcFunc   - A pointwise function giving boundary values
3647 . bcFunc_t - A pointwise function giving the time derivative of the boundary values
3648 - ctx      - An optional user context for bcFunc
3649 
3650   Options Database Keys:
3651 + -bc_<boundary name> <num> - Overrides the boundary ids
3652 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3653 
3654   Level: developer
3655 
3656 .seealso: `PetscDS`, `PetscWeakForm`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `DMLabel`
3657 @*/
3658 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)
3659 {
3660   DSBoundary b = ds->boundary;
3661   PetscInt   n = 0;
3662 
3663   PetscFunctionBegin;
3664   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3665   while (b) {
3666     if (n == bd) break;
3667     b = b->next;
3668     ++n;
3669   }
3670   PetscCheck(b, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bd, n);
3671   if (wf) {
3672     PetscValidPointer(wf, 3);
3673     *wf = b->wf;
3674   }
3675   if (type) {
3676     PetscValidPointer(type, 4);
3677     *type = b->type;
3678   }
3679   if (name) {
3680     PetscValidPointer(name, 5);
3681     *name = b->name;
3682   }
3683   if (label) {
3684     PetscValidPointer(label, 6);
3685     *label = b->label;
3686   }
3687   if (Nv) {
3688     PetscValidIntPointer(Nv, 7);
3689     *Nv = b->Nv;
3690   }
3691   if (values) {
3692     PetscValidPointer(values, 8);
3693     *values = b->values;
3694   }
3695   if (field) {
3696     PetscValidIntPointer(field, 9);
3697     *field = b->field;
3698   }
3699   if (Nc) {
3700     PetscValidIntPointer(Nc, 10);
3701     *Nc = b->Nc;
3702   }
3703   if (comps) {
3704     PetscValidPointer(comps, 11);
3705     *comps = b->comps;
3706   }
3707   if (func) {
3708     PetscValidPointer(func, 12);
3709     *func = b->func;
3710   }
3711   if (func_t) {
3712     PetscValidPointer(func_t, 13);
3713     *func_t = b->func_t;
3714   }
3715   if (ctx) {
3716     PetscValidPointer(ctx, 14);
3717     *ctx = b->ctx;
3718   }
3719   PetscFunctionReturn(PETSC_SUCCESS);
3720 }
3721 
3722 static PetscErrorCode DSBoundaryDuplicate_Internal(DSBoundary b, DSBoundary *bNew)
3723 {
3724   PetscFunctionBegin;
3725   PetscCall(PetscNew(bNew));
3726   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &(*bNew)->wf));
3727   PetscCall(PetscWeakFormCopy(b->wf, (*bNew)->wf));
3728   PetscCall(PetscStrallocpy(b->name, (char **)&((*bNew)->name)));
3729   PetscCall(PetscStrallocpy(b->lname, (char **)&((*bNew)->lname)));
3730   (*bNew)->type  = b->type;
3731   (*bNew)->label = b->label;
3732   (*bNew)->Nv    = b->Nv;
3733   PetscCall(PetscMalloc1(b->Nv, &(*bNew)->values));
3734   PetscCall(PetscArraycpy((*bNew)->values, b->values, b->Nv));
3735   (*bNew)->field = b->field;
3736   (*bNew)->Nc    = b->Nc;
3737   PetscCall(PetscMalloc1(b->Nc, &(*bNew)->comps));
3738   PetscCall(PetscArraycpy((*bNew)->comps, b->comps, b->Nc));
3739   (*bNew)->func   = b->func;
3740   (*bNew)->func_t = b->func_t;
3741   (*bNew)->ctx    = b->ctx;
3742   PetscFunctionReturn(PETSC_SUCCESS);
3743 }
3744 
3745 /*@
3746   PetscDSCopyBoundary - Copy all boundary condition objects to the new problem
3747 
3748   Not collective
3749 
3750   Input Parameters:
3751 + ds        - The source `PetscDS` object
3752 . numFields - The number of selected fields, or `PETSC_DEFAULT` for all fields
3753 - fields    - The selected fields, or NULL for all fields
3754 
3755   Output Parameter:
3756 . newds     - The target `PetscDS`, now with a copy of the boundary conditions
3757 
3758   Level: intermediate
3759 
3760 .seealso: `PetscDS`, `DMBoundary`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3761 @*/
3762 PetscErrorCode PetscDSCopyBoundary(PetscDS ds, PetscInt numFields, const PetscInt fields[], PetscDS newds)
3763 {
3764   DSBoundary b, *lastnext;
3765 
3766   PetscFunctionBegin;
3767   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3768   PetscValidHeaderSpecific(newds, PETSCDS_CLASSID, 4);
3769   if (ds == newds) PetscFunctionReturn(PETSC_SUCCESS);
3770   PetscCall(PetscDSDestroyBoundary(newds));
3771   lastnext = &(newds->boundary);
3772   for (b = ds->boundary; b; b = b->next) {
3773     DSBoundary bNew;
3774     PetscInt   fieldNew = -1;
3775 
3776     if (numFields > 0 && fields) {
3777       PetscInt f;
3778 
3779       for (f = 0; f < numFields; ++f)
3780         if (b->field == fields[f]) break;
3781       if (f == numFields) continue;
3782       fieldNew = f;
3783     }
3784     PetscCall(DSBoundaryDuplicate_Internal(b, &bNew));
3785     bNew->field = fieldNew < 0 ? b->field : fieldNew;
3786     *lastnext   = bNew;
3787     lastnext    = &(bNew->next);
3788   }
3789   PetscFunctionReturn(PETSC_SUCCESS);
3790 }
3791 
3792 /*@
3793   PetscDSDestroyBoundary - Remove all `DMBoundary` objects from the `PetscDS`
3794 
3795   Not collective
3796 
3797   Input Parameter:
3798 . ds - The `PetscDS` object
3799 
3800   Level: intermediate
3801 
3802 .seealso: `PetscDS`, `DMBoundary`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`
3803 @*/
3804 PetscErrorCode PetscDSDestroyBoundary(PetscDS ds)
3805 {
3806   DSBoundary next = ds->boundary;
3807 
3808   PetscFunctionBegin;
3809   while (next) {
3810     DSBoundary b = next;
3811 
3812     next = b->next;
3813     PetscCall(PetscWeakFormDestroy(&b->wf));
3814     PetscCall(PetscFree(b->name));
3815     PetscCall(PetscFree(b->lname));
3816     PetscCall(PetscFree(b->values));
3817     PetscCall(PetscFree(b->comps));
3818     PetscCall(PetscFree(b));
3819   }
3820   PetscFunctionReturn(PETSC_SUCCESS);
3821 }
3822 
3823 /*@
3824   PetscDSSelectDiscretizations - Copy discretizations to the new problem with different field layout
3825 
3826   Not collective
3827 
3828   Input Parameters:
3829 + prob - The `PetscDS` object
3830 . numFields - Number of new fields
3831 - fields - Old field number for each new field
3832 
3833   Output Parameter:
3834 . newprob - The `PetscDS` copy
3835 
3836   Level: intermediate
3837 
3838 .seealso: `PetscDS`, `PetscDSSelectEquations()`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3839 @*/
3840 PetscErrorCode PetscDSSelectDiscretizations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
3841 {
3842   PetscInt Nf, Nfn, fn;
3843 
3844   PetscFunctionBegin;
3845   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3846   if (fields) PetscValidIntPointer(fields, 3);
3847   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 4);
3848   PetscCall(PetscDSGetNumFields(prob, &Nf));
3849   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
3850   numFields = numFields < 0 ? Nf : numFields;
3851   for (fn = 0; fn < numFields; ++fn) {
3852     const PetscInt f = fields ? fields[fn] : fn;
3853     PetscObject    disc;
3854 
3855     if (f >= Nf) continue;
3856     PetscCall(PetscDSGetDiscretization(prob, f, &disc));
3857     PetscCall(PetscDSSetDiscretization(newprob, fn, disc));
3858   }
3859   PetscFunctionReturn(PETSC_SUCCESS);
3860 }
3861 
3862 /*@
3863   PetscDSSelectEquations - Copy pointwise function pointers to the new problem with different field layout
3864 
3865   Not collective
3866 
3867   Input Parameters:
3868 + prob - The `PetscDS` object
3869 . numFields - Number of new fields
3870 - fields - Old field number for each new field
3871 
3872   Output Parameter:
3873 . newprob - The `PetscDS` copy
3874 
3875   Level: intermediate
3876 
3877 .seealso: `PetscDS`, `PetscDSSelectDiscretizations()`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3878 @*/
3879 PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
3880 {
3881   PetscInt Nf, Nfn, fn, gn;
3882 
3883   PetscFunctionBegin;
3884   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3885   if (fields) PetscValidIntPointer(fields, 3);
3886   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 4);
3887   PetscCall(PetscDSGetNumFields(prob, &Nf));
3888   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
3889   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);
3890   for (fn = 0; fn < numFields; ++fn) {
3891     const PetscInt   f = fields ? fields[fn] : fn;
3892     PetscPointFunc   obj;
3893     PetscPointFunc   f0, f1;
3894     PetscBdPointFunc f0Bd, f1Bd;
3895     PetscRiemannFunc r;
3896 
3897     if (f >= Nf) continue;
3898     PetscCall(PetscDSGetObjective(prob, f, &obj));
3899     PetscCall(PetscDSGetResidual(prob, f, &f0, &f1));
3900     PetscCall(PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd));
3901     PetscCall(PetscDSGetRiemannSolver(prob, f, &r));
3902     PetscCall(PetscDSSetObjective(newprob, fn, obj));
3903     PetscCall(PetscDSSetResidual(newprob, fn, f0, f1));
3904     PetscCall(PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd));
3905     PetscCall(PetscDSSetRiemannSolver(newprob, fn, r));
3906     for (gn = 0; gn < numFields; ++gn) {
3907       const PetscInt  g = fields ? fields[gn] : gn;
3908       PetscPointJac   g0, g1, g2, g3;
3909       PetscPointJac   g0p, g1p, g2p, g3p;
3910       PetscBdPointJac g0Bd, g1Bd, g2Bd, g3Bd;
3911 
3912       if (g >= Nf) continue;
3913       PetscCall(PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3));
3914       PetscCall(PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p));
3915       PetscCall(PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd));
3916       PetscCall(PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3));
3917       PetscCall(PetscDSSetJacobianPreconditioner(newprob, fn, gn, g0p, g1p, g2p, g3p));
3918       PetscCall(PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd));
3919     }
3920   }
3921   PetscFunctionReturn(PETSC_SUCCESS);
3922 }
3923 
3924 /*@
3925   PetscDSCopyEquations - Copy all pointwise function pointers to another `PetscDS`
3926 
3927   Not collective
3928 
3929   Input Parameter:
3930 . prob - The `PetscDS` object
3931 
3932   Output Parameter:
3933 . newprob - The `PetscDS` copy
3934 
3935   Level: intermediate
3936 
3937 .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3938 @*/
3939 PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
3940 {
3941   PetscWeakForm wf, newwf;
3942   PetscInt      Nf, Ng;
3943 
3944   PetscFunctionBegin;
3945   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3946   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
3947   PetscCall(PetscDSGetNumFields(prob, &Nf));
3948   PetscCall(PetscDSGetNumFields(newprob, &Ng));
3949   PetscCheck(Nf == Ng, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %" PetscInt_FMT " != %" PetscInt_FMT, Nf, Ng);
3950   PetscCall(PetscDSGetWeakForm(prob, &wf));
3951   PetscCall(PetscDSGetWeakForm(newprob, &newwf));
3952   PetscCall(PetscWeakFormCopy(wf, newwf));
3953   PetscFunctionReturn(PETSC_SUCCESS);
3954 }
3955 
3956 /*@
3957   PetscDSCopyConstants - Copy all constants to another `PetscDS`
3958 
3959   Not collective
3960 
3961   Input Parameter:
3962 . prob - The `PetscDS` object
3963 
3964   Output Parameter:
3965 . newprob - The `PetscDS` copy
3966 
3967   Level: intermediate
3968 
3969 .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3970 @*/
3971 PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
3972 {
3973   PetscInt           Nc;
3974   const PetscScalar *constants;
3975 
3976   PetscFunctionBegin;
3977   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3978   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
3979   PetscCall(PetscDSGetConstants(prob, &Nc, &constants));
3980   PetscCall(PetscDSSetConstants(newprob, Nc, (PetscScalar *)constants));
3981   PetscFunctionReturn(PETSC_SUCCESS);
3982 }
3983 
3984 /*@
3985   PetscDSCopyExactSolutions - Copy all exact solutions to another `PetscDS`
3986 
3987   Not collective
3988 
3989   Input Parameter:
3990 . ds - The `PetscDS` object
3991 
3992   Output Parameter:
3993 . newds - The `PetscDS` copy
3994 
3995   Level: intermediate
3996 
3997 .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3998 @*/
3999 PetscErrorCode PetscDSCopyExactSolutions(PetscDS ds, PetscDS newds)
4000 {
4001   PetscSimplePointFunc sol;
4002   void                *ctx;
4003   PetscInt             Nf, f;
4004 
4005   PetscFunctionBegin;
4006   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4007   PetscValidHeaderSpecific(newds, PETSCDS_CLASSID, 2);
4008   PetscCall(PetscDSGetNumFields(ds, &Nf));
4009   for (f = 0; f < Nf; ++f) {
4010     PetscCall(PetscDSGetExactSolution(ds, f, &sol, &ctx));
4011     PetscCall(PetscDSSetExactSolution(newds, f, sol, ctx));
4012     PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, f, &sol, &ctx));
4013     PetscCall(PetscDSSetExactSolutionTimeDerivative(newds, f, sol, ctx));
4014   }
4015   PetscFunctionReturn(PETSC_SUCCESS);
4016 }
4017 
4018 PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
4019 {
4020   PetscInt dim, Nf, f;
4021 
4022   PetscFunctionBegin;
4023   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
4024   PetscValidPointer(subprob, 3);
4025   if (height == 0) {
4026     *subprob = prob;
4027     PetscFunctionReturn(PETSC_SUCCESS);
4028   }
4029   PetscCall(PetscDSGetNumFields(prob, &Nf));
4030   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
4031   PetscCheck(height <= dim, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %" PetscInt_FMT "], not %" PetscInt_FMT, dim, height);
4032   if (!prob->subprobs) PetscCall(PetscCalloc1(dim, &prob->subprobs));
4033   if (!prob->subprobs[height - 1]) {
4034     PetscInt cdim;
4035 
4036     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)prob), &prob->subprobs[height - 1]));
4037     PetscCall(PetscDSGetCoordinateDimension(prob, &cdim));
4038     PetscCall(PetscDSSetCoordinateDimension(prob->subprobs[height - 1], cdim));
4039     for (f = 0; f < Nf; ++f) {
4040       PetscFE      subfe;
4041       PetscObject  obj;
4042       PetscClassId id;
4043 
4044       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
4045       PetscCall(PetscObjectGetClassId(obj, &id));
4046       if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetHeightSubspace((PetscFE)obj, height, &subfe));
4047       else SETERRQ(PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %" PetscInt_FMT, f);
4048       PetscCall(PetscDSSetDiscretization(prob->subprobs[height - 1], f, (PetscObject)subfe));
4049     }
4050   }
4051   *subprob = prob->subprobs[height - 1];
4052   PetscFunctionReturn(PETSC_SUCCESS);
4053 }
4054 
4055 PetscErrorCode PetscDSGetDiscType_Internal(PetscDS ds, PetscInt f, PetscDiscType *disctype)
4056 {
4057   PetscObject  obj;
4058   PetscClassId id;
4059   PetscInt     Nf;
4060 
4061   PetscFunctionBegin;
4062   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4063   PetscValidPointer(disctype, 3);
4064   *disctype = PETSC_DISC_NONE;
4065   PetscCall(PetscDSGetNumFields(ds, &Nf));
4066   PetscCheck(f < Nf, PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_SIZ, "Field %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
4067   PetscCall(PetscDSGetDiscretization(ds, f, &obj));
4068   if (obj) {
4069     PetscCall(PetscObjectGetClassId(obj, &id));
4070     if (id == PETSCFE_CLASSID) *disctype = PETSC_DISC_FE;
4071     else *disctype = PETSC_DISC_FV;
4072   }
4073   PetscFunctionReturn(PETSC_SUCCESS);
4074 }
4075 
4076 static PetscErrorCode PetscDSDestroy_Basic(PetscDS ds)
4077 {
4078   PetscFunctionBegin;
4079   PetscCall(PetscFree(ds->data));
4080   PetscFunctionReturn(PETSC_SUCCESS);
4081 }
4082 
4083 static PetscErrorCode PetscDSInitialize_Basic(PetscDS ds)
4084 {
4085   PetscFunctionBegin;
4086   ds->ops->setfromoptions = NULL;
4087   ds->ops->setup          = NULL;
4088   ds->ops->view           = NULL;
4089   ds->ops->destroy        = PetscDSDestroy_Basic;
4090   PetscFunctionReturn(PETSC_SUCCESS);
4091 }
4092 
4093 /*MC
4094   PETSCDSBASIC = "basic" - A discrete system with pointwise residual and boundary residual functions
4095 
4096   Level: intermediate
4097 
4098 .seealso: `PetscDSType`, `PetscDSCreate()`, `PetscDSSetType()`
4099 M*/
4100 
4101 PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS ds)
4102 {
4103   PetscDS_Basic *b;
4104 
4105   PetscFunctionBegin;
4106   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4107   PetscCall(PetscNew(&b));
4108   ds->data = b;
4109 
4110   PetscCall(PetscDSInitialize_Basic(ds));
4111   PetscFunctionReturn(PETSC_SUCCESS);
4112 }
4113