xref: /petsc/src/dm/dt/interface/dtds.c (revision a29dfd43bb0c77e2653d3bfa2c953f902720a6d2)
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->numFuncConstants = 3; // Row and col fields, cell size
691   p->dimEmbed         = -1;
692   p->useJacPre        = PETSC_TRUE;
693   p->forceQuad        = PETSC_TRUE;
694   PetscCall(PetscMalloc1(p->numConstants + p->numFuncConstants, &p->constants));
695   PetscCall(PetscWeakFormCreate(comm, &p->wf));
696   PetscCall(PetscArrayzero(p->quadPerm, DM_NUM_POLYTOPES));
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 . ds - 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 ds, PetscInt *numConstants, const PetscScalar *constants[])
2828 {
2829   PetscFunctionBegin;
2830   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2831   if (numConstants) {
2832     PetscAssertPointer(numConstants, 2);
2833     *numConstants = ds->numConstants;
2834   }
2835   if (constants) {
2836     PetscAssertPointer(constants, 3);
2837     *constants = ds->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 + ds           - 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 ds, PetscInt numConstants, PetscScalar constants[])
2857 {
2858   PetscFunctionBegin;
2859   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2860   if (numConstants != ds->numConstants) {
2861     PetscCall(PetscFree(ds->constants));
2862     ds->numConstants = numConstants;
2863     PetscCall(PetscMalloc1(ds->numConstants + ds->numFuncConstants, &ds->constants));
2864   }
2865   if (ds->numConstants) {
2866     PetscAssertPointer(constants, 3);
2867     PetscCall(PetscArraycpy(ds->constants, constants, ds->numConstants));
2868   }
2869   PetscFunctionReturn(PETSC_SUCCESS);
2870 }
2871 
2872 /*@C
2873   PetscDSSetIntegrationParameters - Set the parameters for a particular integration
2874 
2875   Not Collective
2876 
2877   Input Parameters:
2878 + ds     - The `PetscDS` object
2879 . fieldI - The test field for a given point function, or PETSC_DETERMINE
2880 - fieldJ - The basis field for a given point function, or PETSC_DETERMINE
2881 
2882   Level: intermediate
2883 
2884 .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSGetConstants()`, `PetscDSCreate()`
2885 @*/
2886 PetscErrorCode PetscDSSetIntegrationParameters(PetscDS ds, PetscInt fieldI, PetscInt fieldJ)
2887 {
2888   PetscFunctionBegin;
2889   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2890   ds->constants[ds->numConstants]     = fieldI;
2891   ds->constants[ds->numConstants + 1] = fieldJ;
2892   PetscFunctionReturn(PETSC_SUCCESS);
2893 }
2894 
2895 /*@C
2896   PetscDSSetCellParameters - Set the parameters for a particular cell
2897 
2898   Not Collective
2899 
2900   Input Parameters:
2901 + ds     - The `PetscDS` object
2902 - volume - The cell volume
2903 
2904   Level: intermediate
2905 
2906 .seealso: `PetscDS`, `PetscDSSetConstants()`, `PetscDSGetConstants()`, `PetscDSCreate()`
2907 @*/
2908 PetscErrorCode PetscDSSetCellParameters(PetscDS ds, PetscReal volume)
2909 {
2910   PetscFunctionBegin;
2911   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2912   ds->constants[ds->numConstants + 2] = volume;
2913   PetscFunctionReturn(PETSC_SUCCESS);
2914 }
2915 
2916 /*@
2917   PetscDSGetFieldIndex - Returns the index of the given field
2918 
2919   Not Collective
2920 
2921   Input Parameters:
2922 + prob - The `PetscDS` object
2923 - disc - The discretization object
2924 
2925   Output Parameter:
2926 . f - The field number
2927 
2928   Level: beginner
2929 
2930 .seealso: `PetscDS`, `PetscGetDiscretization()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
2931 @*/
2932 PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
2933 {
2934   PetscInt g;
2935 
2936   PetscFunctionBegin;
2937   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2938   PetscAssertPointer(f, 3);
2939   *f = -1;
2940   for (g = 0; g < prob->Nf; ++g) {
2941     if (disc == prob->disc[g]) break;
2942   }
2943   PetscCheck(g != prob->Nf, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
2944   *f = g;
2945   PetscFunctionReturn(PETSC_SUCCESS);
2946 }
2947 
2948 /*@
2949   PetscDSGetFieldSize - Returns the size of the given field in the full space basis
2950 
2951   Not Collective
2952 
2953   Input Parameters:
2954 + prob - The `PetscDS` object
2955 - f    - The field number
2956 
2957   Output Parameter:
2958 . size - The size
2959 
2960   Level: beginner
2961 
2962 .seealso: `PetscDS`, `PetscDSGetFieldOffset()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
2963 @*/
2964 PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
2965 {
2966   PetscFunctionBegin;
2967   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2968   PetscAssertPointer(size, 3);
2969   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);
2970   PetscCall(PetscDSSetUp(prob));
2971   *size = prob->Nb[f];
2972   PetscFunctionReturn(PETSC_SUCCESS);
2973 }
2974 
2975 /*@
2976   PetscDSGetFieldOffset - Returns the offset of the given field in the full space basis
2977 
2978   Not Collective
2979 
2980   Input Parameters:
2981 + prob - The `PetscDS` object
2982 - f    - The field number
2983 
2984   Output Parameter:
2985 . off - The offset
2986 
2987   Level: beginner
2988 
2989 .seealso: `PetscDS`, `PetscDSGetFieldSize()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
2990 @*/
2991 PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
2992 {
2993   PetscInt size, g;
2994 
2995   PetscFunctionBegin;
2996   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2997   PetscAssertPointer(off, 3);
2998   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);
2999   *off = 0;
3000   for (g = 0; g < f; ++g) {
3001     PetscCall(PetscDSGetFieldSize(prob, g, &size));
3002     *off += size;
3003   }
3004   PetscFunctionReturn(PETSC_SUCCESS);
3005 }
3006 
3007 /*@
3008   PetscDSGetFieldOffsetCohesive - Returns the offset of the given field in the full space basis on a cohesive cell
3009 
3010   Not Collective
3011 
3012   Input Parameters:
3013 + ds - The `PetscDS` object
3014 - f  - The field number
3015 
3016   Output Parameter:
3017 . off - The offset
3018 
3019   Level: beginner
3020 
3021 .seealso: `PetscDS`, `PetscDSGetFieldSize()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3022 @*/
3023 PetscErrorCode PetscDSGetFieldOffsetCohesive(PetscDS ds, PetscInt f, PetscInt *off)
3024 {
3025   PetscInt size, g;
3026 
3027   PetscFunctionBegin;
3028   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3029   PetscAssertPointer(off, 3);
3030   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);
3031   *off = 0;
3032   for (g = 0; g < f; ++g) {
3033     PetscBool cohesive;
3034 
3035     PetscCall(PetscDSGetCohesive(ds, g, &cohesive));
3036     PetscCall(PetscDSGetFieldSize(ds, g, &size));
3037     *off += cohesive ? size : size * 2;
3038   }
3039   PetscFunctionReturn(PETSC_SUCCESS);
3040 }
3041 
3042 /*@
3043   PetscDSGetDimensions - Returns the size of the approximation space for each field on an evaluation point
3044 
3045   Not Collective
3046 
3047   Input Parameter:
3048 . prob - The `PetscDS` object
3049 
3050   Output Parameter:
3051 . dimensions - The number of dimensions
3052 
3053   Level: beginner
3054 
3055 .seealso: `PetscDS`, `PetscDSGetComponentOffsets()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3056 @*/
3057 PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
3058 {
3059   PetscFunctionBegin;
3060   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3061   PetscCall(PetscDSSetUp(prob));
3062   PetscAssertPointer(dimensions, 2);
3063   *dimensions = prob->Nb;
3064   PetscFunctionReturn(PETSC_SUCCESS);
3065 }
3066 
3067 /*@
3068   PetscDSGetComponents - Returns the number of components for each field on an evaluation point
3069 
3070   Not Collective
3071 
3072   Input Parameter:
3073 . prob - The `PetscDS` object
3074 
3075   Output Parameter:
3076 . components - The number of components
3077 
3078   Level: beginner
3079 
3080 .seealso: `PetscDS`, `PetscDSGetComponentOffsets()`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3081 @*/
3082 PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
3083 {
3084   PetscFunctionBegin;
3085   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3086   PetscCall(PetscDSSetUp(prob));
3087   PetscAssertPointer(components, 2);
3088   *components = prob->Nc;
3089   PetscFunctionReturn(PETSC_SUCCESS);
3090 }
3091 
3092 /*@
3093   PetscDSGetComponentOffset - Returns the offset of the given field on an evaluation point
3094 
3095   Not Collective
3096 
3097   Input Parameters:
3098 + prob - The `PetscDS` object
3099 - f    - The field number
3100 
3101   Output Parameter:
3102 . off - The offset
3103 
3104   Level: beginner
3105 
3106 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3107 @*/
3108 PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
3109 {
3110   PetscFunctionBegin;
3111   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3112   PetscAssertPointer(off, 3);
3113   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);
3114   PetscCall(PetscDSSetUp(prob));
3115   *off = prob->off[f];
3116   PetscFunctionReturn(PETSC_SUCCESS);
3117 }
3118 
3119 /*@
3120   PetscDSGetComponentOffsets - Returns the offset of each field on an evaluation point
3121 
3122   Not Collective
3123 
3124   Input Parameter:
3125 . prob - The `PetscDS` object
3126 
3127   Output Parameter:
3128 . offsets - The offsets
3129 
3130   Level: beginner
3131 
3132 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3133 @*/
3134 PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
3135 {
3136   PetscFunctionBegin;
3137   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3138   PetscAssertPointer(offsets, 2);
3139   PetscCall(PetscDSSetUp(prob));
3140   *offsets = prob->off;
3141   PetscFunctionReturn(PETSC_SUCCESS);
3142 }
3143 
3144 /*@
3145   PetscDSGetComponentDerivativeOffsets - Returns the offset of each field derivative on an evaluation point
3146 
3147   Not Collective
3148 
3149   Input Parameter:
3150 . prob - The `PetscDS` object
3151 
3152   Output Parameter:
3153 . offsets - The offsets
3154 
3155   Level: beginner
3156 
3157 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3158 @*/
3159 PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
3160 {
3161   PetscFunctionBegin;
3162   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3163   PetscAssertPointer(offsets, 2);
3164   PetscCall(PetscDSSetUp(prob));
3165   *offsets = prob->offDer;
3166   PetscFunctionReturn(PETSC_SUCCESS);
3167 }
3168 
3169 /*@
3170   PetscDSGetComponentOffsetsCohesive - Returns the offset of each field on an evaluation point
3171 
3172   Not Collective
3173 
3174   Input Parameters:
3175 + ds - The `PetscDS` object
3176 - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive
3177 
3178   Output Parameter:
3179 . offsets - The offsets
3180 
3181   Level: beginner
3182 
3183 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3184 @*/
3185 PetscErrorCode PetscDSGetComponentOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
3186 {
3187   PetscFunctionBegin;
3188   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3189   PetscAssertPointer(offsets, 3);
3190   PetscCheck(ds->isCohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
3191   PetscCheck(!(s < 0) && !(s > 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %" PetscInt_FMT " is not in [0, 2]", s);
3192   PetscCall(PetscDSSetUp(ds));
3193   *offsets = ds->offCohesive[s];
3194   PetscFunctionReturn(PETSC_SUCCESS);
3195 }
3196 
3197 /*@
3198   PetscDSGetComponentDerivativeOffsetsCohesive - Returns the offset of each field derivative on an evaluation point
3199 
3200   Not Collective
3201 
3202   Input Parameters:
3203 + ds - The `PetscDS` object
3204 - s  - The cohesive side, 0 for negative, 1 for positive, 2 for cohesive
3205 
3206   Output Parameter:
3207 . offsets - The offsets
3208 
3209   Level: beginner
3210 
3211 .seealso: `PetscDS`, `PetscDSGetNumFields()`, `PetscDSCreate()`
3212 @*/
3213 PetscErrorCode PetscDSGetComponentDerivativeOffsetsCohesive(PetscDS ds, PetscInt s, PetscInt *offsets[])
3214 {
3215   PetscFunctionBegin;
3216   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3217   PetscAssertPointer(offsets, 3);
3218   PetscCheck(ds->isCohesive, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Cohesive offsets are only valid for a cohesive DS");
3219   PetscCheck(!(s < 0) && !(s > 2), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cohesive side %" PetscInt_FMT " is not in [0, 2]", s);
3220   PetscCall(PetscDSSetUp(ds));
3221   *offsets = ds->offDerCohesive[s];
3222   PetscFunctionReturn(PETSC_SUCCESS);
3223 }
3224 
3225 /*@C
3226   PetscDSGetTabulation - Return the basis tabulation at quadrature points for the volume discretization
3227 
3228   Not Collective
3229 
3230   Input Parameter:
3231 . prob - The `PetscDS` object
3232 
3233   Output Parameter:
3234 . T - The basis function and derivatives tabulation at quadrature points for each field
3235 
3236   Level: intermediate
3237 
3238 .seealso: `PetscDS`, `PetscTabulation`, `PetscDSCreate()`
3239 @*/
3240 PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[])
3241 {
3242   PetscFunctionBegin;
3243   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3244   PetscAssertPointer(T, 2);
3245   PetscCall(PetscDSSetUp(prob));
3246   *T = prob->T;
3247   PetscFunctionReturn(PETSC_SUCCESS);
3248 }
3249 
3250 /*@C
3251   PetscDSGetFaceTabulation - Return the basis tabulation at quadrature points on the faces
3252 
3253   Not Collective
3254 
3255   Input Parameter:
3256 . prob - The `PetscDS` object
3257 
3258   Output Parameter:
3259 . Tf - The basis function and derivative tabulation on each local face at quadrature points for each and field
3260 
3261   Level: intermediate
3262 
3263 .seealso: `PetscTabulation`, `PetscDS`, `PetscDSGetTabulation()`, `PetscDSCreate()`
3264 @*/
3265 PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
3266 {
3267   PetscFunctionBegin;
3268   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3269   PetscAssertPointer(Tf, 2);
3270   PetscCall(PetscDSSetUp(prob));
3271   *Tf = prob->Tf;
3272   PetscFunctionReturn(PETSC_SUCCESS);
3273 }
3274 
3275 PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
3276 {
3277   PetscFunctionBegin;
3278   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3279   PetscCall(PetscDSSetUp(prob));
3280   if (u) {
3281     PetscAssertPointer(u, 2);
3282     *u = prob->u;
3283   }
3284   if (u_t) {
3285     PetscAssertPointer(u_t, 3);
3286     *u_t = prob->u_t;
3287   }
3288   if (u_x) {
3289     PetscAssertPointer(u_x, 4);
3290     *u_x = prob->u_x;
3291   }
3292   PetscFunctionReturn(PETSC_SUCCESS);
3293 }
3294 
3295 PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar **f0, PetscScalar **f1, PetscScalar **g0, PetscScalar **g1, PetscScalar **g2, PetscScalar **g3)
3296 {
3297   PetscFunctionBegin;
3298   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3299   PetscCall(PetscDSSetUp(prob));
3300   if (f0) {
3301     PetscAssertPointer(f0, 2);
3302     *f0 = prob->f0;
3303   }
3304   if (f1) {
3305     PetscAssertPointer(f1, 3);
3306     *f1 = prob->f1;
3307   }
3308   if (g0) {
3309     PetscAssertPointer(g0, 4);
3310     *g0 = prob->g0;
3311   }
3312   if (g1) {
3313     PetscAssertPointer(g1, 5);
3314     *g1 = prob->g1;
3315   }
3316   if (g2) {
3317     PetscAssertPointer(g2, 6);
3318     *g2 = prob->g2;
3319   }
3320   if (g3) {
3321     PetscAssertPointer(g3, 7);
3322     *g3 = prob->g3;
3323   }
3324   PetscFunctionReturn(PETSC_SUCCESS);
3325 }
3326 
3327 PetscErrorCode PetscDSGetWorkspace(PetscDS prob, PetscReal **x, PetscScalar **basisReal, PetscScalar **basisDerReal, PetscScalar **testReal, PetscScalar **testDerReal)
3328 {
3329   PetscFunctionBegin;
3330   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3331   PetscCall(PetscDSSetUp(prob));
3332   if (x) {
3333     PetscAssertPointer(x, 2);
3334     *x = prob->x;
3335   }
3336   if (basisReal) {
3337     PetscAssertPointer(basisReal, 3);
3338     *basisReal = prob->basisReal;
3339   }
3340   if (basisDerReal) {
3341     PetscAssertPointer(basisDerReal, 4);
3342     *basisDerReal = prob->basisDerReal;
3343   }
3344   if (testReal) {
3345     PetscAssertPointer(testReal, 5);
3346     *testReal = prob->testReal;
3347   }
3348   if (testDerReal) {
3349     PetscAssertPointer(testDerReal, 6);
3350     *testDerReal = prob->testDerReal;
3351   }
3352   PetscFunctionReturn(PETSC_SUCCESS);
3353 }
3354 
3355 /*@C
3356   PetscDSAddBoundary - Add a boundary condition to the model.
3357 
3358   Collective
3359 
3360   Input Parameters:
3361 + ds       - The PetscDS object
3362 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
3363 . name     - The BC name
3364 . label    - The label defining constrained points
3365 . Nv       - The number of `DMLabel` values for constrained points
3366 . values   - An array of label values for constrained points
3367 . field    - The field to constrain
3368 . Nc       - The number of constrained field components (0 will constrain all fields)
3369 . comps    - An array of constrained component numbers
3370 . bcFunc   - A pointwise function giving boundary values
3371 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3372 - ctx      - An optional user context for bcFunc
3373 
3374   Output Parameter:
3375 . bd - The boundary number
3376 
3377   Options Database Keys:
3378 + -bc_<boundary name> <num>      - Overrides the boundary ids
3379 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3380 
3381   Level: developer
3382 
3383   Note:
3384   Both `bcFunc` and `bcFunc_t` will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
3385 
3386 $ void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
3387 
3388   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
3389 .vb
3390   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
3391               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
3392               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
3393               PetscReal time, const PetscReal x[], PetscScalar bcval[])
3394 .ve
3395 + dim - the spatial dimension
3396 . Nf - the number of fields
3397 . uOff - the offset into u[] and u_t[] for each field
3398 . uOff_x - the offset into u_x[] for each field
3399 . u - each field evaluated at the current point
3400 . u_t - the time derivative of each field evaluated at the current point
3401 . u_x - the gradient of each field evaluated at the current point
3402 . aOff - the offset into a[] and a_t[] for each auxiliary field
3403 . aOff_x - the offset into a_x[] for each auxiliary field
3404 . a - each auxiliary field evaluated at the current point
3405 . a_t - the time derivative of each auxiliary field evaluated at the current point
3406 . a_x - the gradient of auxiliary each field evaluated at the current point
3407 . t - current time
3408 . x - coordinates of the current point
3409 . numConstants - number of constant parameters
3410 . constants - constant parameters
3411 - bcval - output values at the current point
3412 
3413   Notes:
3414   The pointwise functions are used to provide boundary values for essential boundary
3415   conditions. In FEM, they are acting upon by dual basis functionals to generate FEM
3416   coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary
3417   integrals should be performed, using the kernels from `PetscDSSetBdResidual()`.
3418 
3419 .seealso: `PetscDS`, `PetscWeakForm`, `DMLabel`, `DMBoundaryConditionType`, `PetscDSAddBoundaryByName()`, `PetscDSGetBoundary()`, `PetscDSSetResidual()`, `PetscDSSetBdResidual()`
3420 @*/
3421 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)
3422 {
3423   DSBoundary  head = ds->boundary, b;
3424   PetscInt    n    = 0;
3425   const char *lname;
3426 
3427   PetscFunctionBegin;
3428   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3429   PetscValidLogicalCollectiveEnum(ds, type, 2);
3430   PetscAssertPointer(name, 3);
3431   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
3432   PetscValidLogicalCollectiveInt(ds, Nv, 5);
3433   PetscValidLogicalCollectiveInt(ds, field, 7);
3434   PetscValidLogicalCollectiveInt(ds, Nc, 8);
3435   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);
3436   if (Nc > 0) {
3437     PetscInt *fcomps;
3438     PetscInt  c;
3439 
3440     PetscCall(PetscDSGetComponents(ds, &fcomps));
3441     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);
3442     for (c = 0; c < Nc; ++c) {
3443       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);
3444     }
3445   }
3446   PetscCall(PetscNew(&b));
3447   PetscCall(PetscStrallocpy(name, (char **)&b->name));
3448   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
3449   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
3450   PetscCall(PetscMalloc1(Nv, &b->values));
3451   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3452   PetscCall(PetscMalloc1(Nc, &b->comps));
3453   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3454   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
3455   PetscCall(PetscStrallocpy(lname, (char **)&b->lname));
3456   b->type   = type;
3457   b->label  = label;
3458   b->Nv     = Nv;
3459   b->field  = field;
3460   b->Nc     = Nc;
3461   b->func   = bcFunc;
3462   b->func_t = bcFunc_t;
3463   b->ctx    = ctx;
3464   b->next   = NULL;
3465   /* Append to linked list so that we can preserve the order */
3466   if (!head) ds->boundary = b;
3467   while (head) {
3468     if (!head->next) {
3469       head->next = b;
3470       head       = b;
3471     }
3472     head = head->next;
3473     ++n;
3474   }
3475   if (bd) {
3476     PetscAssertPointer(bd, 13);
3477     *bd = n;
3478   }
3479   PetscFunctionReturn(PETSC_SUCCESS);
3480 }
3481 
3482 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
3483 /*@C
3484   PetscDSAddBoundaryByName - Add a boundary condition to the model.
3485 
3486   Collective
3487 
3488   Input Parameters:
3489 + ds       - The `PetscDS` object
3490 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
3491 . name     - The BC name
3492 . lname    - The naem of the label defining constrained points
3493 . Nv       - The number of `DMLabel` values for constrained points
3494 . values   - An array of label values for constrained points
3495 . field    - The field to constrain
3496 . Nc       - The number of constrained field components (0 will constrain all fields)
3497 . comps    - An array of constrained component numbers
3498 . bcFunc   - A pointwise function giving boundary values
3499 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3500 - ctx      - An optional user context for bcFunc
3501 
3502   Output Parameter:
3503 . bd - The boundary number
3504 
3505   Options Database Keys:
3506 + -bc_<boundary name> <num>      - Overrides the boundary ids
3507 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3508 
3509   Calling Sequence of `bcFunc` and `bcFunc_t`:
3510   If the type is `DM_BC_ESSENTIAL`
3511 .vb
3512   void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
3513 .ve
3514   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value,
3515 .vb
3516   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
3517               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
3518               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
3519               PetscReal time, const PetscReal x[], PetscScalar bcval[])
3520 .ve
3521 + dim - the spatial dimension
3522 . Nf - the number of fields
3523 . uOff - the offset into u[] and u_t[] for each field
3524 . uOff_x - the offset into u_x[] for each field
3525 . u - each field evaluated at the current point
3526 . u_t - the time derivative of each field evaluated at the current point
3527 . u_x - the gradient of each field evaluated at the current point
3528 . aOff - the offset into a[] and a_t[] for each auxiliary field
3529 . aOff_x - the offset into a_x[] for each auxiliary field
3530 . a - each auxiliary field evaluated at the current point
3531 . a_t - the time derivative of each auxiliary field evaluated at the current point
3532 . a_x - the gradient of auxiliary each field evaluated at the current point
3533 . t - current time
3534 . x - coordinates of the current point
3535 . numConstants - number of constant parameters
3536 . constants - constant parameters
3537 - bcval - output values at the current point
3538 
3539   Level: developer
3540 
3541   Notes:
3542   The pointwise functions are used to provide boundary values for essential boundary
3543   conditions. In FEM, they are acting upon by dual basis functionals to generate FEM
3544   coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary
3545   integrals should be performed, using the kernels from `PetscDSSetBdResidual()`.
3546 
3547   This function should only be used with `DMFOREST` currently, since labels cannot be defined before the underlying `DMPLEX` is built.
3548 
3549 .seealso: `PetscDS`, `PetscWeakForm`, `DMLabel`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`, `PetscDSSetResidual()`, `PetscDSSetBdResidual()`
3550 @*/
3551 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)
3552 {
3553   DSBoundary head = ds->boundary, b;
3554   PetscInt   n    = 0;
3555 
3556   PetscFunctionBegin;
3557   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3558   PetscValidLogicalCollectiveEnum(ds, type, 2);
3559   PetscAssertPointer(name, 3);
3560   PetscAssertPointer(lname, 4);
3561   PetscValidLogicalCollectiveInt(ds, Nv, 5);
3562   PetscValidLogicalCollectiveInt(ds, field, 7);
3563   PetscValidLogicalCollectiveInt(ds, Nc, 8);
3564   PetscCall(PetscNew(&b));
3565   PetscCall(PetscStrallocpy(name, (char **)&b->name));
3566   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &b->wf));
3567   PetscCall(PetscWeakFormSetNumFields(b->wf, ds->Nf));
3568   PetscCall(PetscMalloc1(Nv, &b->values));
3569   if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3570   PetscCall(PetscMalloc1(Nc, &b->comps));
3571   if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3572   PetscCall(PetscStrallocpy(lname, (char **)&b->lname));
3573   b->type   = type;
3574   b->label  = NULL;
3575   b->Nv     = Nv;
3576   b->field  = field;
3577   b->Nc     = Nc;
3578   b->func   = bcFunc;
3579   b->func_t = bcFunc_t;
3580   b->ctx    = ctx;
3581   b->next   = NULL;
3582   /* Append to linked list so that we can preserve the order */
3583   if (!head) ds->boundary = b;
3584   while (head) {
3585     if (!head->next) {
3586       head->next = b;
3587       head       = b;
3588     }
3589     head = head->next;
3590     ++n;
3591   }
3592   if (bd) {
3593     PetscAssertPointer(bd, 13);
3594     *bd = n;
3595   }
3596   PetscFunctionReturn(PETSC_SUCCESS);
3597 }
3598 
3599 /*@C
3600   PetscDSUpdateBoundary - Change a boundary condition for the model.
3601 
3602   Input Parameters:
3603 + ds       - The `PetscDS` object
3604 . bd       - The boundary condition number
3605 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
3606 . name     - The BC name
3607 . label    - The label defining constrained points
3608 . Nv       - The number of `DMLabel` ids for constrained points
3609 . values   - An array of ids for constrained points
3610 . field    - The field to constrain
3611 . Nc       - The number of constrained field components
3612 . comps    - An array of constrained component numbers
3613 . bcFunc   - A pointwise function giving boundary values
3614 . bcFunc_t - A pointwise function giving the time derivative of the boundary values, or NULL
3615 - ctx      - An optional user context for bcFunc
3616 
3617   Level: developer
3618 
3619   Notes:
3620   The pointwise functions are used to provide boundary values for essential boundary
3621   conditions. In FEM, they are acting upon by dual basis functionals to generate FEM
3622   coefficients which are fixed. Natural boundary conditions signal to PETSc that boundary
3623   integrals should be performed, using the kernels from `PetscDSSetBdResidual()`.
3624 
3625   The boundary condition number is the order in which it was registered. The user can get the number of boundary conditions from `PetscDSGetNumBoundary()`.
3626   See `PetscDSAddBoundary()` for a description of the calling sequences for the callbacks.
3627 
3628 .seealso: `PetscDS`, `PetscWeakForm`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`, `PetscDSGetNumBoundary()`, `DMLabel`
3629 @*/
3630 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)
3631 {
3632   DSBoundary b = ds->boundary;
3633   PetscInt   n = 0;
3634 
3635   PetscFunctionBegin;
3636   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3637   while (b) {
3638     if (n == bd) break;
3639     b = b->next;
3640     ++n;
3641   }
3642   PetscCheck(b, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bd, n);
3643   if (name) {
3644     PetscCall(PetscFree(b->name));
3645     PetscCall(PetscStrallocpy(name, (char **)&b->name));
3646   }
3647   b->type = type;
3648   if (label) {
3649     const char *name;
3650 
3651     b->label = label;
3652     PetscCall(PetscFree(b->lname));
3653     PetscCall(PetscObjectGetName((PetscObject)label, &name));
3654     PetscCall(PetscStrallocpy(name, (char **)&b->lname));
3655   }
3656   if (Nv >= 0) {
3657     b->Nv = Nv;
3658     PetscCall(PetscFree(b->values));
3659     PetscCall(PetscMalloc1(Nv, &b->values));
3660     if (Nv) PetscCall(PetscArraycpy(b->values, values, Nv));
3661   }
3662   if (field >= 0) b->field = field;
3663   if (Nc >= 0) {
3664     b->Nc = Nc;
3665     PetscCall(PetscFree(b->comps));
3666     PetscCall(PetscMalloc1(Nc, &b->comps));
3667     if (Nc) PetscCall(PetscArraycpy(b->comps, comps, Nc));
3668   }
3669   if (bcFunc) b->func = bcFunc;
3670   if (bcFunc_t) b->func_t = bcFunc_t;
3671   if (ctx) b->ctx = ctx;
3672   PetscFunctionReturn(PETSC_SUCCESS);
3673 }
3674 
3675 /*@
3676   PetscDSGetNumBoundary - Get the number of registered BC
3677 
3678   Input Parameter:
3679 . ds - The `PetscDS` object
3680 
3681   Output Parameter:
3682 . numBd - The number of BC
3683 
3684   Level: intermediate
3685 
3686 .seealso: `PetscDS`, `PetscDSAddBoundary()`, `PetscDSGetBoundary()`
3687 @*/
3688 PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
3689 {
3690   DSBoundary b = ds->boundary;
3691 
3692   PetscFunctionBegin;
3693   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3694   PetscAssertPointer(numBd, 2);
3695   *numBd = 0;
3696   while (b) {
3697     ++(*numBd);
3698     b = b->next;
3699   }
3700   PetscFunctionReturn(PETSC_SUCCESS);
3701 }
3702 
3703 /*@C
3704   PetscDSGetBoundary - Gets a boundary condition to the model
3705 
3706   Input Parameters:
3707 + ds - The `PetscDS` object
3708 - bd - The BC number
3709 
3710   Output Parameters:
3711 + wf     - The `PetscWeakForm` holding the pointwise functions
3712 . type   - The type of condition, e.g. `DM_BC_ESSENTIAL`/`DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
3713 . name   - The BC name
3714 . label  - The label defining constrained points
3715 . Nv     - The number of `DMLabel` ids for constrained points
3716 . values - An array of ids for constrained points
3717 . field  - The field to constrain
3718 . Nc     - The number of constrained field components
3719 . comps  - An array of constrained component numbers
3720 . func   - A pointwise function giving boundary values
3721 . func_t - A pointwise function giving the time derivative of the boundary values
3722 - ctx    - An optional user context for bcFunc
3723 
3724   Options Database Keys:
3725 + -bc_<boundary name> <num>      - Overrides the boundary ids
3726 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3727 
3728   Level: developer
3729 
3730 .seealso: `PetscDS`, `PetscWeakForm`, `DMBoundaryConditionType`, `PetscDSAddBoundary()`, `DMLabel`
3731 @*/
3732 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)
3733 {
3734   DSBoundary b = ds->boundary;
3735   PetscInt   n = 0;
3736 
3737   PetscFunctionBegin;
3738   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3739   while (b) {
3740     if (n == bd) break;
3741     b = b->next;
3742     ++n;
3743   }
3744   PetscCheck(b, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", bd, n);
3745   if (wf) {
3746     PetscAssertPointer(wf, 3);
3747     *wf = b->wf;
3748   }
3749   if (type) {
3750     PetscAssertPointer(type, 4);
3751     *type = b->type;
3752   }
3753   if (name) {
3754     PetscAssertPointer(name, 5);
3755     *name = b->name;
3756   }
3757   if (label) {
3758     PetscAssertPointer(label, 6);
3759     *label = b->label;
3760   }
3761   if (Nv) {
3762     PetscAssertPointer(Nv, 7);
3763     *Nv = b->Nv;
3764   }
3765   if (values) {
3766     PetscAssertPointer(values, 8);
3767     *values = b->values;
3768   }
3769   if (field) {
3770     PetscAssertPointer(field, 9);
3771     *field = b->field;
3772   }
3773   if (Nc) {
3774     PetscAssertPointer(Nc, 10);
3775     *Nc = b->Nc;
3776   }
3777   if (comps) {
3778     PetscAssertPointer(comps, 11);
3779     *comps = b->comps;
3780   }
3781   if (func) {
3782     PetscAssertPointer(func, 12);
3783     *func = b->func;
3784   }
3785   if (func_t) {
3786     PetscAssertPointer(func_t, 13);
3787     *func_t = b->func_t;
3788   }
3789   if (ctx) {
3790     PetscAssertPointer(ctx, 14);
3791     *ctx = b->ctx;
3792   }
3793   PetscFunctionReturn(PETSC_SUCCESS);
3794 }
3795 
3796 /*@
3797   PetscDSUpdateBoundaryLabels - Update `DMLabel` in each boundary condition using the label name and the input `DM`
3798 
3799   Not Collective
3800 
3801   Input Parameters:
3802 + ds - The source `PetscDS` object
3803 - dm - The `DM` holding labels
3804 
3805   Level: intermediate
3806 
3807 .seealso: `PetscDS`, `DMBoundary`, `DM`, `PetscDSCopyBoundary()`, `PetscDSCreate()`, `DMGetLabel()`
3808 @*/
3809 PetscErrorCode PetscDSUpdateBoundaryLabels(PetscDS ds, DM dm)
3810 {
3811   DSBoundary b;
3812 
3813   PetscFunctionBegin;
3814   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3815   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
3816   for (b = ds->boundary; b; b = b->next) {
3817     if (b->lname) PetscCall(DMGetLabel(dm, b->lname, &b->label));
3818   }
3819   PetscFunctionReturn(PETSC_SUCCESS);
3820 }
3821 
3822 static PetscErrorCode DSBoundaryDuplicate_Internal(DSBoundary b, DSBoundary *bNew)
3823 {
3824   PetscFunctionBegin;
3825   PetscCall(PetscNew(bNew));
3826   PetscCall(PetscWeakFormCreate(PETSC_COMM_SELF, &(*bNew)->wf));
3827   PetscCall(PetscWeakFormCopy(b->wf, (*bNew)->wf));
3828   PetscCall(PetscStrallocpy(b->name, (char **)&((*bNew)->name)));
3829   PetscCall(PetscStrallocpy(b->lname, (char **)&((*bNew)->lname)));
3830   (*bNew)->type  = b->type;
3831   (*bNew)->label = b->label;
3832   (*bNew)->Nv    = b->Nv;
3833   PetscCall(PetscMalloc1(b->Nv, &(*bNew)->values));
3834   PetscCall(PetscArraycpy((*bNew)->values, b->values, b->Nv));
3835   (*bNew)->field = b->field;
3836   (*bNew)->Nc    = b->Nc;
3837   PetscCall(PetscMalloc1(b->Nc, &(*bNew)->comps));
3838   PetscCall(PetscArraycpy((*bNew)->comps, b->comps, b->Nc));
3839   (*bNew)->func   = b->func;
3840   (*bNew)->func_t = b->func_t;
3841   (*bNew)->ctx    = b->ctx;
3842   PetscFunctionReturn(PETSC_SUCCESS);
3843 }
3844 
3845 /*@
3846   PetscDSCopyBoundary - Copy all boundary condition objects to the new problem
3847 
3848   Not Collective
3849 
3850   Input Parameters:
3851 + ds        - The source `PetscDS` object
3852 . numFields - The number of selected fields, or `PETSC_DEFAULT` for all fields
3853 - fields    - The selected fields, or NULL for all fields
3854 
3855   Output Parameter:
3856 . newds - The target `PetscDS`, now with a copy of the boundary conditions
3857 
3858   Level: intermediate
3859 
3860 .seealso: `PetscDS`, `DMBoundary`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3861 @*/
3862 PetscErrorCode PetscDSCopyBoundary(PetscDS ds, PetscInt numFields, const PetscInt fields[], PetscDS newds)
3863 {
3864   DSBoundary b, *lastnext;
3865 
3866   PetscFunctionBegin;
3867   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3868   PetscValidHeaderSpecific(newds, PETSCDS_CLASSID, 4);
3869   if (ds == newds) PetscFunctionReturn(PETSC_SUCCESS);
3870   PetscCall(PetscDSDestroyBoundary(newds));
3871   lastnext = &newds->boundary;
3872   for (b = ds->boundary; b; b = b->next) {
3873     DSBoundary bNew;
3874     PetscInt   fieldNew = -1;
3875 
3876     if (numFields > 0 && fields) {
3877       PetscInt f;
3878 
3879       for (f = 0; f < numFields; ++f)
3880         if (b->field == fields[f]) break;
3881       if (f == numFields) continue;
3882       fieldNew = f;
3883     }
3884     PetscCall(DSBoundaryDuplicate_Internal(b, &bNew));
3885     bNew->field = fieldNew < 0 ? b->field : fieldNew;
3886     *lastnext   = bNew;
3887     lastnext    = &bNew->next;
3888   }
3889   PetscFunctionReturn(PETSC_SUCCESS);
3890 }
3891 
3892 /*@
3893   PetscDSDestroyBoundary - Remove all `DMBoundary` objects from the `PetscDS`
3894 
3895   Not Collective
3896 
3897   Input Parameter:
3898 . ds - The `PetscDS` object
3899 
3900   Level: intermediate
3901 
3902 .seealso: `PetscDS`, `DMBoundary`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`
3903 @*/
3904 PetscErrorCode PetscDSDestroyBoundary(PetscDS ds)
3905 {
3906   DSBoundary next = ds->boundary;
3907 
3908   PetscFunctionBegin;
3909   while (next) {
3910     DSBoundary b = next;
3911 
3912     next = b->next;
3913     PetscCall(PetscWeakFormDestroy(&b->wf));
3914     PetscCall(PetscFree(b->name));
3915     PetscCall(PetscFree(b->lname));
3916     PetscCall(PetscFree(b->values));
3917     PetscCall(PetscFree(b->comps));
3918     PetscCall(PetscFree(b));
3919   }
3920   PetscFunctionReturn(PETSC_SUCCESS);
3921 }
3922 
3923 /*@
3924   PetscDSSelectDiscretizations - Copy discretizations to the new problem with different field layout
3925 
3926   Not Collective
3927 
3928   Input Parameters:
3929 + prob      - The `PetscDS` object
3930 . numFields - Number of new fields
3931 - fields    - Old field number for each new field
3932 
3933   Output Parameter:
3934 . newprob - The `PetscDS` copy
3935 
3936   Level: intermediate
3937 
3938 .seealso: `PetscDS`, `PetscDSSelectEquations()`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3939 @*/
3940 PetscErrorCode PetscDSSelectDiscretizations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
3941 {
3942   PetscInt Nf, Nfn, fn;
3943 
3944   PetscFunctionBegin;
3945   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3946   if (fields) PetscAssertPointer(fields, 3);
3947   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 4);
3948   PetscCall(PetscDSGetNumFields(prob, &Nf));
3949   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
3950   numFields = numFields < 0 ? Nf : numFields;
3951   for (fn = 0; fn < numFields; ++fn) {
3952     const PetscInt f = fields ? fields[fn] : fn;
3953     PetscObject    disc;
3954 
3955     if (f >= Nf) continue;
3956     PetscCall(PetscDSGetDiscretization(prob, f, &disc));
3957     PetscCall(PetscDSSetDiscretization(newprob, fn, disc));
3958   }
3959   PetscFunctionReturn(PETSC_SUCCESS);
3960 }
3961 
3962 /*@
3963   PetscDSSelectEquations - Copy pointwise function pointers to the new problem with different field layout
3964 
3965   Not Collective
3966 
3967   Input Parameters:
3968 + prob      - The `PetscDS` object
3969 . numFields - Number of new fields
3970 - fields    - Old field number for each new field
3971 
3972   Output Parameter:
3973 . newprob - The `PetscDS` copy
3974 
3975   Level: intermediate
3976 
3977 .seealso: `PetscDS`, `PetscDSSelectDiscretizations()`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
3978 @*/
3979 PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
3980 {
3981   PetscInt Nf, Nfn, fn, gn;
3982 
3983   PetscFunctionBegin;
3984   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3985   if (fields) PetscAssertPointer(fields, 3);
3986   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 4);
3987   PetscCall(PetscDSGetNumFields(prob, &Nf));
3988   PetscCall(PetscDSGetNumFields(newprob, &Nfn));
3989   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);
3990   for (fn = 0; fn < numFields; ++fn) {
3991     const PetscInt   f = fields ? fields[fn] : fn;
3992     PetscPointFunc   obj;
3993     PetscPointFunc   f0, f1;
3994     PetscBdPointFunc f0Bd, f1Bd;
3995     PetscRiemannFunc r;
3996 
3997     if (f >= Nf) continue;
3998     PetscCall(PetscDSGetObjective(prob, f, &obj));
3999     PetscCall(PetscDSGetResidual(prob, f, &f0, &f1));
4000     PetscCall(PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd));
4001     PetscCall(PetscDSGetRiemannSolver(prob, f, &r));
4002     PetscCall(PetscDSSetObjective(newprob, fn, obj));
4003     PetscCall(PetscDSSetResidual(newprob, fn, f0, f1));
4004     PetscCall(PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd));
4005     PetscCall(PetscDSSetRiemannSolver(newprob, fn, r));
4006     for (gn = 0; gn < numFields; ++gn) {
4007       const PetscInt  g = fields ? fields[gn] : gn;
4008       PetscPointJac   g0, g1, g2, g3;
4009       PetscPointJac   g0p, g1p, g2p, g3p;
4010       PetscBdPointJac g0Bd, g1Bd, g2Bd, g3Bd;
4011 
4012       if (g >= Nf) continue;
4013       PetscCall(PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3));
4014       PetscCall(PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p));
4015       PetscCall(PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd));
4016       PetscCall(PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3));
4017       PetscCall(PetscDSSetJacobianPreconditioner(newprob, fn, gn, g0p, g1p, g2p, g3p));
4018       PetscCall(PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd));
4019     }
4020   }
4021   PetscFunctionReturn(PETSC_SUCCESS);
4022 }
4023 
4024 /*@
4025   PetscDSCopyEquations - Copy all pointwise function pointers to another `PetscDS`
4026 
4027   Not Collective
4028 
4029   Input Parameter:
4030 . prob - The `PetscDS` object
4031 
4032   Output Parameter:
4033 . newprob - The `PetscDS` copy
4034 
4035   Level: intermediate
4036 
4037 .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
4038 @*/
4039 PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
4040 {
4041   PetscWeakForm wf, newwf;
4042   PetscInt      Nf, Ng;
4043 
4044   PetscFunctionBegin;
4045   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
4046   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
4047   PetscCall(PetscDSGetNumFields(prob, &Nf));
4048   PetscCall(PetscDSGetNumFields(newprob, &Ng));
4049   PetscCheck(Nf == Ng, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %" PetscInt_FMT " != %" PetscInt_FMT, Nf, Ng);
4050   PetscCall(PetscDSGetWeakForm(prob, &wf));
4051   PetscCall(PetscDSGetWeakForm(newprob, &newwf));
4052   PetscCall(PetscWeakFormCopy(wf, newwf));
4053   PetscFunctionReturn(PETSC_SUCCESS);
4054 }
4055 
4056 /*@
4057   PetscDSCopyConstants - Copy all constants to another `PetscDS`
4058 
4059   Not Collective
4060 
4061   Input Parameter:
4062 . prob - The `PetscDS` object
4063 
4064   Output Parameter:
4065 . newprob - The `PetscDS` copy
4066 
4067   Level: intermediate
4068 
4069 .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
4070 @*/
4071 PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
4072 {
4073   PetscInt           Nc;
4074   const PetscScalar *constants;
4075 
4076   PetscFunctionBegin;
4077   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
4078   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
4079   PetscCall(PetscDSGetConstants(prob, &Nc, &constants));
4080   PetscCall(PetscDSSetConstants(newprob, Nc, (PetscScalar *)constants));
4081   PetscFunctionReturn(PETSC_SUCCESS);
4082 }
4083 
4084 /*@
4085   PetscDSCopyExactSolutions - Copy all exact solutions to another `PetscDS`
4086 
4087   Not Collective
4088 
4089   Input Parameter:
4090 . ds - The `PetscDS` object
4091 
4092   Output Parameter:
4093 . newds - The `PetscDS` copy
4094 
4095   Level: intermediate
4096 
4097 .seealso: `PetscDS`, `PetscDSCopyBoundary()`, `PetscDSCopyEquations()`, `PetscDSSetResidual()`, `PetscDSSetJacobian()`, `PetscDSSetRiemannSolver()`, `PetscDSSetBdResidual()`, `PetscDSSetBdJacobian()`, `PetscDSCreate()`
4098 @*/
4099 PetscErrorCode PetscDSCopyExactSolutions(PetscDS ds, PetscDS newds)
4100 {
4101   PetscSimplePointFn *sol;
4102   void               *ctx;
4103   PetscInt            Nf, f;
4104 
4105   PetscFunctionBegin;
4106   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4107   PetscValidHeaderSpecific(newds, PETSCDS_CLASSID, 2);
4108   PetscCall(PetscDSGetNumFields(ds, &Nf));
4109   for (f = 0; f < Nf; ++f) {
4110     PetscCall(PetscDSGetExactSolution(ds, f, &sol, &ctx));
4111     PetscCall(PetscDSSetExactSolution(newds, f, sol, ctx));
4112     PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, f, &sol, &ctx));
4113     PetscCall(PetscDSSetExactSolutionTimeDerivative(newds, f, sol, ctx));
4114   }
4115   PetscFunctionReturn(PETSC_SUCCESS);
4116 }
4117 
4118 PetscErrorCode PetscDSCopy(PetscDS ds, DM dmNew, PetscDS dsNew)
4119 {
4120   DSBoundary b;
4121   PetscInt   cdim, Nf, f, d;
4122   PetscBool  isCohesive;
4123   void      *ctx;
4124 
4125   PetscFunctionBegin;
4126   PetscCall(PetscDSCopyConstants(ds, dsNew));
4127   PetscCall(PetscDSCopyExactSolutions(ds, dsNew));
4128   PetscCall(PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew));
4129   PetscCall(PetscDSCopyEquations(ds, dsNew));
4130   PetscCall(PetscDSGetNumFields(ds, &Nf));
4131   for (f = 0; f < Nf; ++f) {
4132     PetscCall(PetscDSGetContext(ds, f, &ctx));
4133     PetscCall(PetscDSSetContext(dsNew, f, ctx));
4134     PetscCall(PetscDSGetCohesive(ds, f, &isCohesive));
4135     PetscCall(PetscDSSetCohesive(dsNew, f, isCohesive));
4136     PetscCall(PetscDSGetJetDegree(ds, f, &d));
4137     PetscCall(PetscDSSetJetDegree(dsNew, f, d));
4138   }
4139   if (Nf) {
4140     PetscCall(PetscDSGetCoordinateDimension(ds, &cdim));
4141     PetscCall(PetscDSSetCoordinateDimension(dsNew, cdim));
4142   }
4143   PetscCall(PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew));
4144   for (b = dsNew->boundary; b; b = b->next) {
4145     PetscCall(DMGetLabel(dmNew, b->lname, &b->label));
4146     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
4147     //PetscCheck(b->label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
4148   }
4149   PetscFunctionReturn(PETSC_SUCCESS);
4150 }
4151 
4152 PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
4153 {
4154   PetscInt dim, Nf, f;
4155 
4156   PetscFunctionBegin;
4157   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
4158   PetscAssertPointer(subprob, 3);
4159   if (height == 0) {
4160     *subprob = prob;
4161     PetscFunctionReturn(PETSC_SUCCESS);
4162   }
4163   PetscCall(PetscDSGetNumFields(prob, &Nf));
4164   PetscCall(PetscDSGetSpatialDimension(prob, &dim));
4165   PetscCheck(height <= dim, PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %" PetscInt_FMT "], not %" PetscInt_FMT, dim, height);
4166   if (!prob->subprobs) PetscCall(PetscCalloc1(dim, &prob->subprobs));
4167   if (!prob->subprobs[height - 1]) {
4168     PetscInt cdim;
4169 
4170     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)prob), &prob->subprobs[height - 1]));
4171     PetscCall(PetscDSGetCoordinateDimension(prob, &cdim));
4172     PetscCall(PetscDSSetCoordinateDimension(prob->subprobs[height - 1], cdim));
4173     for (f = 0; f < Nf; ++f) {
4174       PetscFE      subfe;
4175       PetscObject  obj;
4176       PetscClassId id;
4177 
4178       PetscCall(PetscDSGetDiscretization(prob, f, &obj));
4179       PetscCall(PetscObjectGetClassId(obj, &id));
4180       if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetHeightSubspace((PetscFE)obj, height, &subfe));
4181       else SETERRQ(PetscObjectComm((PetscObject)prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %" PetscInt_FMT, f);
4182       PetscCall(PetscDSSetDiscretization(prob->subprobs[height - 1], f, (PetscObject)subfe));
4183     }
4184   }
4185   *subprob = prob->subprobs[height - 1];
4186   PetscFunctionReturn(PETSC_SUCCESS);
4187 }
4188 
4189 PetscErrorCode PetscDSPermuteQuadPoint(PetscDS ds, PetscInt ornt, PetscInt field, PetscInt q, PetscInt *qperm)
4190 {
4191   IS              permIS;
4192   PetscQuadrature quad;
4193   DMPolytopeType  ct;
4194   const PetscInt *perm;
4195   PetscInt        Na, Nq;
4196 
4197   PetscFunctionBeginHot;
4198   PetscCall(PetscFEGetQuadrature((PetscFE)ds->disc[field], &quad));
4199   PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL));
4200   PetscCall(PetscQuadratureGetCellType(quad, &ct));
4201   PetscCheck(q >= 0 && q < Nq, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Quadrature point %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", q, Nq);
4202   Na = DMPolytopeTypeGetNumArrangements(ct) / 2;
4203   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);
4204   if (!ds->quadPerm[(PetscInt)ct]) PetscCall(PetscQuadratureComputePermutations(quad, NULL, &ds->quadPerm[(PetscInt)ct]));
4205   permIS = ds->quadPerm[(PetscInt)ct][ornt + Na];
4206   PetscCall(ISGetIndices(permIS, &perm));
4207   *qperm = perm[q];
4208   PetscCall(ISRestoreIndices(permIS, &perm));
4209   PetscFunctionReturn(PETSC_SUCCESS);
4210 }
4211 
4212 PetscErrorCode PetscDSGetDiscType_Internal(PetscDS ds, PetscInt f, PetscDiscType *disctype)
4213 {
4214   PetscObject  obj;
4215   PetscClassId id;
4216   PetscInt     Nf;
4217 
4218   PetscFunctionBegin;
4219   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4220   PetscAssertPointer(disctype, 3);
4221   *disctype = PETSC_DISC_NONE;
4222   PetscCall(PetscDSGetNumFields(ds, &Nf));
4223   PetscCheck(f < Nf, PetscObjectComm((PetscObject)ds), PETSC_ERR_ARG_SIZ, "Field %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
4224   PetscCall(PetscDSGetDiscretization(ds, f, &obj));
4225   if (obj) {
4226     PetscCall(PetscObjectGetClassId(obj, &id));
4227     if (id == PETSCFE_CLASSID) *disctype = PETSC_DISC_FE;
4228     else *disctype = PETSC_DISC_FV;
4229   }
4230   PetscFunctionReturn(PETSC_SUCCESS);
4231 }
4232 
4233 static PetscErrorCode PetscDSDestroy_Basic(PetscDS ds)
4234 {
4235   PetscFunctionBegin;
4236   PetscCall(PetscFree(ds->data));
4237   PetscFunctionReturn(PETSC_SUCCESS);
4238 }
4239 
4240 static PetscErrorCode PetscDSInitialize_Basic(PetscDS ds)
4241 {
4242   PetscFunctionBegin;
4243   ds->ops->setfromoptions = NULL;
4244   ds->ops->setup          = NULL;
4245   ds->ops->view           = NULL;
4246   ds->ops->destroy        = PetscDSDestroy_Basic;
4247   PetscFunctionReturn(PETSC_SUCCESS);
4248 }
4249 
4250 /*MC
4251   PETSCDSBASIC = "basic" - A discrete system with pointwise residual and boundary residual functions
4252 
4253   Level: intermediate
4254 
4255 .seealso: `PetscDSType`, `PetscDSCreate()`, `PetscDSSetType()`
4256 M*/
4257 
4258 PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS ds)
4259 {
4260   PetscDS_Basic *b;
4261 
4262   PetscFunctionBegin;
4263   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
4264   PetscCall(PetscNew(&b));
4265   ds->data = b;
4266 
4267   PetscCall(PetscDSInitialize_Basic(ds));
4268   PetscFunctionReturn(PETSC_SUCCESS);
4269 }
4270