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