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