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