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