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