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