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