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