xref: /petsc/src/dm/dt/interface/dtds.c (revision ea13f565a9e7eeb46a1941ff623f2af24053d663)
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   PetscDSGetImplicit - Returns the flag for implicit solve for this field. This is just a guide for IMEX
916 
917   Not collective
918 
919   Input Parameters:
920 + prob - The PetscDS object
921 - f - The field number
922 
923   Output Parameter:
924 . implicit - The flag indicating what kind of solve to use for this field
925 
926   Level: developer
927 
928 .seealso: PetscDSSetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
929 @*/
930 PetscErrorCode PetscDSGetImplicit(PetscDS prob, PetscInt f, PetscBool *implicit)
931 {
932   PetscFunctionBegin;
933   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
934   PetscValidPointer(implicit, 3);
935   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);
936   *implicit = prob->implicit[f];
937   PetscFunctionReturn(0);
938 }
939 
940 /*@
941   PetscDSSetImplicit - Set the flag for implicit solve for this field. This is just a guide for IMEX
942 
943   Not collective
944 
945   Input Parameters:
946 + prob - The PetscDS object
947 . f - The field number
948 - implicit - The flag indicating what kind of solve to use for this field
949 
950   Level: developer
951 
952 .seealso: PetscDSGetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
953 @*/
954 PetscErrorCode PetscDSSetImplicit(PetscDS prob, PetscInt f, PetscBool implicit)
955 {
956   PetscFunctionBegin;
957   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
958   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);
959   prob->implicit[f] = implicit;
960   PetscFunctionReturn(0);
961 }
962 
963 PetscErrorCode PetscDSGetObjective(PetscDS prob, PetscInt f,
964                                    void (**obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
965                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
966                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
967                                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
968 {
969   PetscFunctionBegin;
970   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
971   PetscValidPointer(obj, 2);
972   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);
973   *obj = prob->obj[f];
974   PetscFunctionReturn(0);
975 }
976 
977 PetscErrorCode PetscDSSetObjective(PetscDS prob, PetscInt f,
978                                    void (*obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
979                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
980                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
981                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
982 {
983   PetscErrorCode ierr;
984 
985   PetscFunctionBegin;
986   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
987   if (obj) PetscValidFunction(obj, 2);
988   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
989   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
990   prob->obj[f] = obj;
991   PetscFunctionReturn(0);
992 }
993 
994 /*@C
995   PetscDSGetResidual - Get the pointwise residual function for a given test field
996 
997   Not collective
998 
999   Input Parameters:
1000 + prob - The PetscDS
1001 - f    - The test field number
1002 
1003   Output Parameters:
1004 + f0 - integrand for the test function term
1005 - f1 - integrand for the test function gradient term
1006 
1007   Note: We are using a first order FEM model for the weak form:
1008 
1009   \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)
1010 
1011 The calling sequence for the callbacks f0 and f1 is given by:
1012 
1013 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1014 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1015 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1016 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
1017 
1018 + dim - the spatial dimension
1019 . Nf - the number of fields
1020 . uOff - the offset into u[] and u_t[] for each field
1021 . uOff_x - the offset into u_x[] for each field
1022 . u - each field evaluated at the current point
1023 . u_t - the time derivative of each field evaluated at the current point
1024 . u_x - the gradient of each field evaluated at the current point
1025 . aOff - the offset into a[] and a_t[] for each auxiliary field
1026 . aOff_x - the offset into a_x[] for each auxiliary field
1027 . a - each auxiliary field evaluated at the current point
1028 . a_t - the time derivative of each auxiliary field evaluated at the current point
1029 . a_x - the gradient of auxiliary each field evaluated at the current point
1030 . t - current time
1031 . x - coordinates of the current point
1032 . numConstants - number of constant parameters
1033 . constants - constant parameters
1034 - f0 - output values at the current point
1035 
1036   Level: intermediate
1037 
1038 .seealso: PetscDSSetResidual()
1039 @*/
1040 PetscErrorCode PetscDSGetResidual(PetscDS prob, PetscInt f,
1041                                   void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1042                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1043                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1044                                               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1045                                   void (**f1)(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[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1049 {
1050   PetscFunctionBegin;
1051   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1052   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);
1053   if (f0) {PetscValidPointer(f0, 3); *f0 = prob->f[f*2+0];}
1054   if (f1) {PetscValidPointer(f1, 4); *f1 = prob->f[f*2+1];}
1055   PetscFunctionReturn(0);
1056 }
1057 
1058 /*@C
1059   PetscDSSetResidual - Set the pointwise residual function for a given test field
1060 
1061   Not collective
1062 
1063   Input Parameters:
1064 + prob - The PetscDS
1065 . f    - The test field number
1066 . f0 - integrand for the test function term
1067 - f1 - integrand for the test function gradient term
1068 
1069   Note: We are using a first order FEM model for the weak form:
1070 
1071   \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)
1072 
1073 The calling sequence for the callbacks f0 and f1 is given by:
1074 
1075 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1076 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1077 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1078 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
1079 
1080 + dim - the spatial dimension
1081 . Nf - the number of fields
1082 . uOff - the offset into u[] and u_t[] for each field
1083 . uOff_x - the offset into u_x[] for each field
1084 . u - each field evaluated at the current point
1085 . u_t - the time derivative of each field evaluated at the current point
1086 . u_x - the gradient of each field evaluated at the current point
1087 . aOff - the offset into a[] and a_t[] for each auxiliary field
1088 . aOff_x - the offset into a_x[] for each auxiliary field
1089 . a - each auxiliary field evaluated at the current point
1090 . a_t - the time derivative of each auxiliary field evaluated at the current point
1091 . a_x - the gradient of auxiliary each field evaluated at the current point
1092 . t - current time
1093 . x - coordinates of the current point
1094 . numConstants - number of constant parameters
1095 . constants - constant parameters
1096 - f0 - output values at the current point
1097 
1098   Level: intermediate
1099 
1100 .seealso: PetscDSGetResidual()
1101 @*/
1102 PetscErrorCode PetscDSSetResidual(PetscDS prob, PetscInt f,
1103                                   void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1104                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1105                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1106                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1107                                   void (*f1)(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[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1111 {
1112   PetscErrorCode ierr;
1113 
1114   PetscFunctionBegin;
1115   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1116   if (f0) PetscValidFunction(f0, 3);
1117   if (f1) PetscValidFunction(f1, 4);
1118   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1119   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1120   prob->f[f*2+0] = f0;
1121   prob->f[f*2+1] = f1;
1122   PetscFunctionReturn(0);
1123 }
1124 
1125 /*@C
1126   PetscDSHasJacobian - Signals that Jacobian functions have been set
1127 
1128   Not collective
1129 
1130   Input Parameter:
1131 . prob - The PetscDS
1132 
1133   Output Parameter:
1134 . hasJac - flag that pointwise function for the Jacobian has been set
1135 
1136   Level: intermediate
1137 
1138 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1139 @*/
1140 PetscErrorCode PetscDSHasJacobian(PetscDS prob, PetscBool *hasJac)
1141 {
1142   PetscInt f, g, h;
1143 
1144   PetscFunctionBegin;
1145   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1146   *hasJac = PETSC_FALSE;
1147   for (f = 0; f < prob->Nf; ++f) {
1148     for (g = 0; g < prob->Nf; ++g) {
1149       for (h = 0; h < 4; ++h) {
1150         if (prob->g[(f*prob->Nf + g)*4+h]) *hasJac = PETSC_TRUE;
1151       }
1152     }
1153   }
1154   PetscFunctionReturn(0);
1155 }
1156 
1157 /*@C
1158   PetscDSGetJacobian - Get the pointwise Jacobian function for given test and basis field
1159 
1160   Not collective
1161 
1162   Input Parameters:
1163 + prob - The PetscDS
1164 . f    - The test field number
1165 - g    - The field number
1166 
1167   Output Parameters:
1168 + g0 - integrand for the test and basis function term
1169 . g1 - integrand for the test function and basis function gradient term
1170 . g2 - integrand for the test function gradient and basis function term
1171 - g3 - integrand for the test function gradient and basis function gradient term
1172 
1173   Note: We are using a first order FEM model for the weak form:
1174 
1175   \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
1176 
1177 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1178 
1179 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1180 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1181 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1182 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1183 
1184 + dim - the spatial dimension
1185 . Nf - the number of fields
1186 . uOff - the offset into u[] and u_t[] for each field
1187 . uOff_x - the offset into u_x[] for each field
1188 . u - each field evaluated at the current point
1189 . u_t - the time derivative of each field evaluated at the current point
1190 . u_x - the gradient of each field evaluated at the current point
1191 . aOff - the offset into a[] and a_t[] for each auxiliary field
1192 . aOff_x - the offset into a_x[] for each auxiliary field
1193 . a - each auxiliary field evaluated at the current point
1194 . a_t - the time derivative of each auxiliary field evaluated at the current point
1195 . a_x - the gradient of auxiliary each field evaluated at the current point
1196 . t - current time
1197 . u_tShift - the multiplier a for dF/dU_t
1198 . x - coordinates of the current point
1199 . numConstants - number of constant parameters
1200 . constants - constant parameters
1201 - g0 - output values at the current point
1202 
1203   Level: intermediate
1204 
1205 .seealso: PetscDSSetJacobian()
1206 @*/
1207 PetscErrorCode PetscDSGetJacobian(PetscDS prob, PetscInt f, PetscInt g,
1208                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1209                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1210                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1211                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1212                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1213                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1214                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1215                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1216                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1217                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1218                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1219                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1220                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1221                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1222                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1223                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1224 {
1225   PetscFunctionBegin;
1226   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1227   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);
1228   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);
1229   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->g[(f*prob->Nf + g)*4+0];}
1230   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->g[(f*prob->Nf + g)*4+1];}
1231   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->g[(f*prob->Nf + g)*4+2];}
1232   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->g[(f*prob->Nf + g)*4+3];}
1233   PetscFunctionReturn(0);
1234 }
1235 
1236 /*@C
1237   PetscDSSetJacobian - Set the pointwise Jacobian function for given test and basis fields
1238 
1239   Not collective
1240 
1241   Input Parameters:
1242 + prob - The PetscDS
1243 . f    - The test field number
1244 . g    - The field number
1245 . g0 - integrand for the test and basis function term
1246 . g1 - integrand for the test function and basis function gradient term
1247 . g2 - integrand for the test function gradient and basis function term
1248 - g3 - integrand for the test function gradient and basis function gradient term
1249 
1250   Note: We are using a first order FEM model for the weak form:
1251 
1252   \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
1253 
1254 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1255 
1256 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1257 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1258 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1259 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1260 
1261 + dim - the spatial dimension
1262 . Nf - the number of fields
1263 . uOff - the offset into u[] and u_t[] for each field
1264 . uOff_x - the offset into u_x[] for each field
1265 . u - each field evaluated at the current point
1266 . u_t - the time derivative of each field evaluated at the current point
1267 . u_x - the gradient of each field evaluated at the current point
1268 . aOff - the offset into a[] and a_t[] for each auxiliary field
1269 . aOff_x - the offset into a_x[] for each auxiliary field
1270 . a - each auxiliary field evaluated at the current point
1271 . a_t - the time derivative of each auxiliary field evaluated at the current point
1272 . a_x - the gradient of auxiliary each field evaluated at the current point
1273 . t - current time
1274 . u_tShift - the multiplier a for dF/dU_t
1275 . x - coordinates of the current point
1276 . numConstants - number of constant parameters
1277 . constants - constant parameters
1278 - g0 - output values at the current point
1279 
1280   Level: intermediate
1281 
1282 .seealso: PetscDSGetJacobian()
1283 @*/
1284 PetscErrorCode PetscDSSetJacobian(PetscDS prob, PetscInt f, PetscInt g,
1285                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1286                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1287                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1288                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1289                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1290                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1291                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1292                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1293                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1294                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1295                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1296                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1297                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1298                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1299                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1300                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1301 {
1302   PetscErrorCode ierr;
1303 
1304   PetscFunctionBegin;
1305   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1306   if (g0) PetscValidFunction(g0, 4);
1307   if (g1) PetscValidFunction(g1, 5);
1308   if (g2) PetscValidFunction(g2, 6);
1309   if (g3) PetscValidFunction(g3, 7);
1310   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1311   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1312   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1313   prob->g[(f*prob->Nf + g)*4+0] = g0;
1314   prob->g[(f*prob->Nf + g)*4+1] = g1;
1315   prob->g[(f*prob->Nf + g)*4+2] = g2;
1316   prob->g[(f*prob->Nf + g)*4+3] = g3;
1317   PetscFunctionReturn(0);
1318 }
1319 
1320 /*@C
1321   PetscDSUseJacobianPreconditioner - Whether to construct a Jacobian preconditioner
1322 
1323   Not collective
1324 
1325   Input Parameters:
1326 + prob - The PetscDS
1327 - useJacPre - flag that enables construction of a Jacobian preconditioner
1328 
1329   Level: intermediate
1330 
1331 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1332 @*/
1333 PetscErrorCode PetscDSUseJacobianPreconditioner(PetscDS prob, PetscBool useJacPre)
1334 {
1335   PetscFunctionBegin;
1336   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1337   prob->useJacPre = useJacPre;
1338   PetscFunctionReturn(0);
1339 }
1340 
1341 /*@C
1342   PetscDSHasJacobianPreconditioner - Signals that a Jacobian preconditioner matrix has been set
1343 
1344   Not collective
1345 
1346   Input Parameter:
1347 . prob - The PetscDS
1348 
1349   Output Parameter:
1350 . hasJacPre - flag that pointwise function for Jacobian preconditioner matrix has been set
1351 
1352   Level: intermediate
1353 
1354 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1355 @*/
1356 PetscErrorCode PetscDSHasJacobianPreconditioner(PetscDS prob, PetscBool *hasJacPre)
1357 {
1358   PetscInt f, g, h;
1359 
1360   PetscFunctionBegin;
1361   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1362   *hasJacPre = PETSC_FALSE;
1363   if (!prob->useJacPre) PetscFunctionReturn(0);
1364   for (f = 0; f < prob->Nf; ++f) {
1365     for (g = 0; g < prob->Nf; ++g) {
1366       for (h = 0; h < 4; ++h) {
1367         if (prob->gp[(f*prob->Nf + g)*4+h]) *hasJacPre = PETSC_TRUE;
1368       }
1369     }
1370   }
1371   PetscFunctionReturn(0);
1372 }
1373 
1374 /*@C
1375   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.
1376 
1377   Not collective
1378 
1379   Input Parameters:
1380 + prob - The PetscDS
1381 . f    - The test field number
1382 - g    - The field number
1383 
1384   Output Parameters:
1385 + g0 - integrand for the test and basis function term
1386 . g1 - integrand for the test function and basis function gradient term
1387 . g2 - integrand for the test function gradient and basis function term
1388 - g3 - integrand for the test function gradient and basis function gradient term
1389 
1390   Note: We are using a first order FEM model for the weak form:
1391 
1392   \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
1393 
1394 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1395 
1396 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1397 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1398 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1399 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1400 
1401 + dim - the spatial dimension
1402 . Nf - the number of fields
1403 . uOff - the offset into u[] and u_t[] for each field
1404 . uOff_x - the offset into u_x[] for each field
1405 . u - each field evaluated at the current point
1406 . u_t - the time derivative of each field evaluated at the current point
1407 . u_x - the gradient of each field evaluated at the current point
1408 . aOff - the offset into a[] and a_t[] for each auxiliary field
1409 . aOff_x - the offset into a_x[] for each auxiliary field
1410 . a - each auxiliary field evaluated at the current point
1411 . a_t - the time derivative of each auxiliary field evaluated at the current point
1412 . a_x - the gradient of auxiliary each field evaluated at the current point
1413 . t - current time
1414 . u_tShift - the multiplier a for dF/dU_t
1415 . x - coordinates of the current point
1416 . numConstants - number of constant parameters
1417 . constants - constant parameters
1418 - g0 - output values at the current point
1419 
1420   Level: intermediate
1421 
1422 .seealso: PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1423 @*/
1424 PetscErrorCode PetscDSGetJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
1425                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1426                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1427                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1428                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1429                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1430                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1431                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1432                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1433                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1434                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1435                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1436                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1437                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1438                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1439                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1440                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1441 {
1442   PetscFunctionBegin;
1443   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1444   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);
1445   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);
1446   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gp[(f*prob->Nf + g)*4+0];}
1447   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gp[(f*prob->Nf + g)*4+1];}
1448   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gp[(f*prob->Nf + g)*4+2];}
1449   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gp[(f*prob->Nf + g)*4+3];}
1450   PetscFunctionReturn(0);
1451 }
1452 
1453 /*@C
1454   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.
1455 
1456   Not collective
1457 
1458   Input Parameters:
1459 + prob - The PetscDS
1460 . f    - The test field number
1461 . g    - The field number
1462 . g0 - integrand for the test and basis function term
1463 . g1 - integrand for the test function and basis function gradient term
1464 . g2 - integrand for the test function gradient and basis function term
1465 - g3 - integrand for the test function gradient and basis function gradient term
1466 
1467   Note: We are using a first order FEM model for the weak form:
1468 
1469   \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
1470 
1471 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1472 
1473 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1474 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1475 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1476 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1477 
1478 + dim - the spatial dimension
1479 . Nf - the number of fields
1480 . uOff - the offset into u[] and u_t[] for each field
1481 . uOff_x - the offset into u_x[] for each field
1482 . u - each field evaluated at the current point
1483 . u_t - the time derivative of each field evaluated at the current point
1484 . u_x - the gradient of each field evaluated at the current point
1485 . aOff - the offset into a[] and a_t[] for each auxiliary field
1486 . aOff_x - the offset into a_x[] for each auxiliary field
1487 . a - each auxiliary field evaluated at the current point
1488 . a_t - the time derivative of each auxiliary field evaluated at the current point
1489 . a_x - the gradient of auxiliary each field evaluated at the current point
1490 . t - current time
1491 . u_tShift - the multiplier a for dF/dU_t
1492 . x - coordinates of the current point
1493 . numConstants - number of constant parameters
1494 . constants - constant parameters
1495 - g0 - output values at the current point
1496 
1497   Level: intermediate
1498 
1499 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobian()
1500 @*/
1501 PetscErrorCode PetscDSSetJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
1502                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1503                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1504                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1505                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1506                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1507                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1508                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1509                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1510                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1511                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1512                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1513                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1514                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1515                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1516                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1517                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1518 {
1519   PetscErrorCode ierr;
1520 
1521   PetscFunctionBegin;
1522   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1523   if (g0) PetscValidFunction(g0, 4);
1524   if (g1) PetscValidFunction(g1, 5);
1525   if (g2) PetscValidFunction(g2, 6);
1526   if (g3) PetscValidFunction(g3, 7);
1527   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1528   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1529   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1530   prob->gp[(f*prob->Nf + g)*4+0] = g0;
1531   prob->gp[(f*prob->Nf + g)*4+1] = g1;
1532   prob->gp[(f*prob->Nf + g)*4+2] = g2;
1533   prob->gp[(f*prob->Nf + g)*4+3] = g3;
1534   PetscFunctionReturn(0);
1535 }
1536 
1537 /*@C
1538   PetscDSHasDynamicJacobian - Signals that a dynamic Jacobian, dF/du_t, has been set
1539 
1540   Not collective
1541 
1542   Input Parameter:
1543 . prob - The PetscDS
1544 
1545   Output Parameter:
1546 . hasDynJac - flag that pointwise function for dynamic Jacobian has been set
1547 
1548   Level: intermediate
1549 
1550 .seealso: PetscDSGetDynamicJacobian(), PetscDSSetDynamicJacobian(), PetscDSGetJacobian()
1551 @*/
1552 PetscErrorCode PetscDSHasDynamicJacobian(PetscDS prob, PetscBool *hasDynJac)
1553 {
1554   PetscInt f, g, h;
1555 
1556   PetscFunctionBegin;
1557   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1558   *hasDynJac = PETSC_FALSE;
1559   for (f = 0; f < prob->Nf; ++f) {
1560     for (g = 0; g < prob->Nf; ++g) {
1561       for (h = 0; h < 4; ++h) {
1562         if (prob->gt[(f*prob->Nf + g)*4+h]) *hasDynJac = PETSC_TRUE;
1563       }
1564     }
1565   }
1566   PetscFunctionReturn(0);
1567 }
1568 
1569 /*@C
1570   PetscDSGetDynamicJacobian - Get the pointwise dynamic Jacobian, dF/du_t, function for given test and basis field
1571 
1572   Not collective
1573 
1574   Input Parameters:
1575 + prob - The PetscDS
1576 . f    - The test field number
1577 - g    - The field number
1578 
1579   Output Parameters:
1580 + g0 - integrand for the test and basis function term
1581 . g1 - integrand for the test function and basis function gradient term
1582 . g2 - integrand for the test function gradient and basis function term
1583 - g3 - integrand for the test function gradient and basis function gradient term
1584 
1585   Note: We are using a first order FEM model for the weak form:
1586 
1587   \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
1588 
1589 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1590 
1591 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1592 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1593 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1594 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1595 
1596 + dim - the spatial dimension
1597 . Nf - the number of fields
1598 . uOff - the offset into u[] and u_t[] for each field
1599 . uOff_x - the offset into u_x[] for each field
1600 . u - each field evaluated at the current point
1601 . u_t - the time derivative of each field evaluated at the current point
1602 . u_x - the gradient of each field evaluated at the current point
1603 . aOff - the offset into a[] and a_t[] for each auxiliary field
1604 . aOff_x - the offset into a_x[] for each auxiliary field
1605 . a - each auxiliary field evaluated at the current point
1606 . a_t - the time derivative of each auxiliary field evaluated at the current point
1607 . a_x - the gradient of auxiliary each field evaluated at the current point
1608 . t - current time
1609 . u_tShift - the multiplier a for dF/dU_t
1610 . x - coordinates of the current point
1611 . numConstants - number of constant parameters
1612 . constants - constant parameters
1613 - g0 - output values at the current point
1614 
1615   Level: intermediate
1616 
1617 .seealso: PetscDSSetJacobian()
1618 @*/
1619 PetscErrorCode PetscDSGetDynamicJacobian(PetscDS prob, PetscInt f, PetscInt g,
1620                                          void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1621                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1622                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1623                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1624                                          void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1625                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1626                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1627                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1628                                          void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1629                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1630                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1631                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1632                                          void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1633                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1634                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1635                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1636 {
1637   PetscFunctionBegin;
1638   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1639   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);
1640   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);
1641   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gt[(f*prob->Nf + g)*4+0];}
1642   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gt[(f*prob->Nf + g)*4+1];}
1643   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gt[(f*prob->Nf + g)*4+2];}
1644   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gt[(f*prob->Nf + g)*4+3];}
1645   PetscFunctionReturn(0);
1646 }
1647 
1648 /*@C
1649   PetscDSSetDynamicJacobian - Set the pointwise dynamic Jacobian, dF/du_t, function for given test and basis fields
1650 
1651   Not collective
1652 
1653   Input Parameters:
1654 + prob - The PetscDS
1655 . f    - The test field number
1656 . g    - The field number
1657 . g0 - integrand for the test and basis function term
1658 . g1 - integrand for the test function and basis function gradient term
1659 . g2 - integrand for the test function gradient and basis function term
1660 - g3 - integrand for the test function gradient and basis function gradient term
1661 
1662   Note: We are using a first order FEM model for the weak form:
1663 
1664   \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
1665 
1666 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1667 
1668 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1669 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1670 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1671 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1672 
1673 + dim - the spatial dimension
1674 . Nf - the number of fields
1675 . uOff - the offset into u[] and u_t[] for each field
1676 . uOff_x - the offset into u_x[] for each field
1677 . u - each field evaluated at the current point
1678 . u_t - the time derivative of each field evaluated at the current point
1679 . u_x - the gradient of each field evaluated at the current point
1680 . aOff - the offset into a[] and a_t[] for each auxiliary field
1681 . aOff_x - the offset into a_x[] for each auxiliary field
1682 . a - each auxiliary field evaluated at the current point
1683 . a_t - the time derivative of each auxiliary field evaluated at the current point
1684 . a_x - the gradient of auxiliary each field evaluated at the current point
1685 . t - current time
1686 . u_tShift - the multiplier a for dF/dU_t
1687 . x - coordinates of the current point
1688 . numConstants - number of constant parameters
1689 . constants - constant parameters
1690 - g0 - output values at the current point
1691 
1692   Level: intermediate
1693 
1694 .seealso: PetscDSGetJacobian()
1695 @*/
1696 PetscErrorCode PetscDSSetDynamicJacobian(PetscDS prob, PetscInt f, PetscInt g,
1697                                          void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1698                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1699                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1700                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1701                                          void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1702                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1703                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1704                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1705                                          void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1706                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1707                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1708                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1709                                          void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1710                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1711                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1712                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1713 {
1714   PetscErrorCode ierr;
1715 
1716   PetscFunctionBegin;
1717   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1718   if (g0) PetscValidFunction(g0, 4);
1719   if (g1) PetscValidFunction(g1, 5);
1720   if (g2) PetscValidFunction(g2, 6);
1721   if (g3) PetscValidFunction(g3, 7);
1722   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1723   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1724   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1725   prob->gt[(f*prob->Nf + g)*4+0] = g0;
1726   prob->gt[(f*prob->Nf + g)*4+1] = g1;
1727   prob->gt[(f*prob->Nf + g)*4+2] = g2;
1728   prob->gt[(f*prob->Nf + g)*4+3] = g3;
1729   PetscFunctionReturn(0);
1730 }
1731 
1732 /*@C
1733   PetscDSGetRiemannSolver - Returns the Riemann solver for the given field
1734 
1735   Not collective
1736 
1737   Input Arguments:
1738 + prob - The PetscDS object
1739 - f    - The field number
1740 
1741   Output Argument:
1742 . r    - Riemann solver
1743 
1744   Calling sequence for r:
1745 
1746 $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)
1747 
1748 + dim  - The spatial dimension
1749 . Nf   - The number of fields
1750 . x    - The coordinates at a point on the interface
1751 . n    - The normal vector to the interface
1752 . uL   - The state vector to the left of the interface
1753 . uR   - The state vector to the right of the interface
1754 . flux - output array of flux through the interface
1755 . numConstants - number of constant parameters
1756 . constants - constant parameters
1757 - ctx  - optional user context
1758 
1759   Level: intermediate
1760 
1761 .seealso: PetscDSSetRiemannSolver()
1762 @*/
1763 PetscErrorCode PetscDSGetRiemannSolver(PetscDS prob, PetscInt f,
1764                                        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))
1765 {
1766   PetscFunctionBegin;
1767   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1768   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);
1769   PetscValidPointer(r, 3);
1770   *r = prob->r[f];
1771   PetscFunctionReturn(0);
1772 }
1773 
1774 /*@C
1775   PetscDSSetRiemannSolver - Sets the Riemann solver for the given field
1776 
1777   Not collective
1778 
1779   Input Arguments:
1780 + prob - The PetscDS object
1781 . f    - The field number
1782 - r    - Riemann solver
1783 
1784   Calling sequence for r:
1785 
1786 $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)
1787 
1788 + dim  - The spatial dimension
1789 . Nf   - The number of fields
1790 . x    - The coordinates at a point on the interface
1791 . n    - The normal vector to the interface
1792 . uL   - The state vector to the left of the interface
1793 . uR   - The state vector to the right of the interface
1794 . flux - output array of flux through the interface
1795 . numConstants - number of constant parameters
1796 . constants - constant parameters
1797 - ctx  - optional user context
1798 
1799   Level: intermediate
1800 
1801 .seealso: PetscDSGetRiemannSolver()
1802 @*/
1803 PetscErrorCode PetscDSSetRiemannSolver(PetscDS prob, PetscInt f,
1804                                        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))
1805 {
1806   PetscErrorCode ierr;
1807 
1808   PetscFunctionBegin;
1809   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1810   if (r) PetscValidFunction(r, 3);
1811   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1812   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1813   prob->r[f] = r;
1814   PetscFunctionReturn(0);
1815 }
1816 
1817 /*@C
1818   PetscDSGetUpdate - Get the pointwise update function for a given field
1819 
1820   Not collective
1821 
1822   Input Parameters:
1823 + prob - The PetscDS
1824 - f    - The field number
1825 
1826   Output Parameters:
1827 . update - update function
1828 
1829   Note: The calling sequence for the callback update is given by:
1830 
1831 $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1832 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1833 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1834 $        PetscReal t, const PetscReal x[], PetscScalar uNew[])
1835 
1836 + dim - the spatial dimension
1837 . Nf - the number of fields
1838 . uOff - the offset into u[] and u_t[] for each field
1839 . uOff_x - the offset into u_x[] for each field
1840 . u - each field evaluated at the current point
1841 . u_t - the time derivative of each field evaluated at the current point
1842 . u_x - the gradient of each field evaluated at the current point
1843 . aOff - the offset into a[] and a_t[] for each auxiliary field
1844 . aOff_x - the offset into a_x[] for each auxiliary field
1845 . a - each auxiliary field evaluated at the current point
1846 . a_t - the time derivative of each auxiliary field evaluated at the current point
1847 . a_x - the gradient of auxiliary each field evaluated at the current point
1848 . t - current time
1849 . x - coordinates of the current point
1850 - uNew - new value for field at the current point
1851 
1852   Level: intermediate
1853 
1854 .seealso: PetscDSSetUpdate(), PetscDSSetResidual()
1855 @*/
1856 PetscErrorCode PetscDSGetUpdate(PetscDS prob, PetscInt f,
1857                                   void (**update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1858                                                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1859                                                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1860                                                   PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
1861 {
1862   PetscFunctionBegin;
1863   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1864   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);
1865   if (update) {PetscValidPointer(update, 3); *update = prob->update[f];}
1866   PetscFunctionReturn(0);
1867 }
1868 
1869 /*@C
1870   PetscDSSetUpdate - Set the pointwise update function for a given field
1871 
1872   Not collective
1873 
1874   Input Parameters:
1875 + prob   - The PetscDS
1876 . f      - The field number
1877 - update - update function
1878 
1879   Note: The calling sequence for the callback update is given by:
1880 
1881 $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1882 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1883 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1884 $        PetscReal t, const PetscReal x[], PetscScalar uNew[])
1885 
1886 + dim - the spatial dimension
1887 . Nf - the number of fields
1888 . uOff - the offset into u[] and u_t[] for each field
1889 . uOff_x - the offset into u_x[] for each field
1890 . u - each field evaluated at the current point
1891 . u_t - the time derivative of each field evaluated at the current point
1892 . u_x - the gradient of each field evaluated at the current point
1893 . aOff - the offset into a[] and a_t[] for each auxiliary field
1894 . aOff_x - the offset into a_x[] for each auxiliary field
1895 . a - each auxiliary field evaluated at the current point
1896 . a_t - the time derivative of each auxiliary field evaluated at the current point
1897 . a_x - the gradient of auxiliary each field evaluated at the current point
1898 . t - current time
1899 . x - coordinates of the current point
1900 - uNew - new field values at the current point
1901 
1902   Level: intermediate
1903 
1904 .seealso: PetscDSGetResidual()
1905 @*/
1906 PetscErrorCode PetscDSSetUpdate(PetscDS prob, PetscInt f,
1907                                 void (*update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1908                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1909                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1910                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
1911 {
1912   PetscErrorCode ierr;
1913 
1914   PetscFunctionBegin;
1915   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1916   if (update) PetscValidFunction(update, 3);
1917   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1918   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1919   prob->update[f] = update;
1920   PetscFunctionReturn(0);
1921 }
1922 
1923 PetscErrorCode PetscDSGetContext(PetscDS prob, PetscInt f, void **ctx)
1924 {
1925   PetscFunctionBegin;
1926   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1927   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);
1928   PetscValidPointer(ctx, 3);
1929   *ctx = prob->ctx[f];
1930   PetscFunctionReturn(0);
1931 }
1932 
1933 PetscErrorCode PetscDSSetContext(PetscDS prob, PetscInt f, void *ctx)
1934 {
1935   PetscErrorCode ierr;
1936 
1937   PetscFunctionBegin;
1938   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1939   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1940   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1941   prob->ctx[f] = ctx;
1942   PetscFunctionReturn(0);
1943 }
1944 
1945 /*@C
1946   PetscDSGetBdResidual - Get the pointwise boundary residual function for a given test field
1947 
1948   Not collective
1949 
1950   Input Parameters:
1951 + prob - The PetscDS
1952 - f    - The test field number
1953 
1954   Output Parameters:
1955 + f0 - boundary integrand for the test function term
1956 - f1 - boundary integrand for the test function gradient term
1957 
1958   Note: We are using a first order FEM model for the weak form:
1959 
1960   \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
1961 
1962 The calling sequence for the callbacks f0 and f1 is given by:
1963 
1964 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1965 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1966 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1967 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
1968 
1969 + dim - the spatial dimension
1970 . Nf - the number of fields
1971 . uOff - the offset into u[] and u_t[] for each field
1972 . uOff_x - the offset into u_x[] for each field
1973 . u - each field evaluated at the current point
1974 . u_t - the time derivative of each field evaluated at the current point
1975 . u_x - the gradient of each field evaluated at the current point
1976 . aOff - the offset into a[] and a_t[] for each auxiliary field
1977 . aOff_x - the offset into a_x[] for each auxiliary field
1978 . a - each auxiliary field evaluated at the current point
1979 . a_t - the time derivative of each auxiliary field evaluated at the current point
1980 . a_x - the gradient of auxiliary each field evaluated at the current point
1981 . t - current time
1982 . x - coordinates of the current point
1983 . n - unit normal at the current point
1984 . numConstants - number of constant parameters
1985 . constants - constant parameters
1986 - f0 - output values at the current point
1987 
1988   Level: intermediate
1989 
1990 .seealso: PetscDSSetBdResidual()
1991 @*/
1992 PetscErrorCode PetscDSGetBdResidual(PetscDS prob, PetscInt f,
1993                                     void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1994                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1995                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1996                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1997                                     void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1998                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1999                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2000                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
2001 {
2002   PetscFunctionBegin;
2003   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2004   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);
2005   if (f0) {PetscValidPointer(f0, 3); *f0 = prob->fBd[f*2+0];}
2006   if (f1) {PetscValidPointer(f1, 4); *f1 = prob->fBd[f*2+1];}
2007   PetscFunctionReturn(0);
2008 }
2009 
2010 /*@C
2011   PetscDSSetBdResidual - Get the pointwise boundary residual function for a given test field
2012 
2013   Not collective
2014 
2015   Input Parameters:
2016 + prob - The PetscDS
2017 . f    - The test field number
2018 . f0 - boundary integrand for the test function term
2019 - f1 - boundary integrand for the test function gradient term
2020 
2021   Note: We are using a first order FEM model for the weak form:
2022 
2023   \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
2024 
2025 The calling sequence for the callbacks f0 and f1 is given by:
2026 
2027 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2028 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2029 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2030 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
2031 
2032 + dim - the spatial dimension
2033 . Nf - the number of fields
2034 . uOff - the offset into u[] and u_t[] for each field
2035 . uOff_x - the offset into u_x[] for each field
2036 . u - each field evaluated at the current point
2037 . u_t - the time derivative of each field evaluated at the current point
2038 . u_x - the gradient of each field evaluated at the current point
2039 . aOff - the offset into a[] and a_t[] for each auxiliary field
2040 . aOff_x - the offset into a_x[] for each auxiliary field
2041 . a - each auxiliary field evaluated at the current point
2042 . a_t - the time derivative of each auxiliary field evaluated at the current point
2043 . a_x - the gradient of auxiliary each field evaluated at the current point
2044 . t - current time
2045 . x - coordinates of the current point
2046 . n - unit normal at the current point
2047 . numConstants - number of constant parameters
2048 . constants - constant parameters
2049 - f0 - output values at the current point
2050 
2051   Level: intermediate
2052 
2053 .seealso: PetscDSGetBdResidual()
2054 @*/
2055 PetscErrorCode PetscDSSetBdResidual(PetscDS prob, PetscInt f,
2056                                     void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2057                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2058                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2059                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
2060                                     void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2061                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2062                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2063                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
2064 {
2065   PetscErrorCode ierr;
2066 
2067   PetscFunctionBegin;
2068   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2069   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2070   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
2071   if (f0) {PetscValidFunction(f0, 3); prob->fBd[f*2+0] = f0;}
2072   if (f1) {PetscValidFunction(f1, 4); prob->fBd[f*2+1] = f1;}
2073   PetscFunctionReturn(0);
2074 }
2075 
2076 /*@
2077   PetscDSHasBdJacobian - Signals that boundary Jacobian functions have been set
2078 
2079   Not collective
2080 
2081   Input Parameter:
2082 . prob - The PetscDS
2083 
2084   Output Parameter:
2085 . hasBdJac - flag that pointwise function for the boundary Jacobian has been set
2086 
2087   Level: intermediate
2088 
2089 .seealso: PetscDSHasJacobian(), PetscDSSetBdJacobian(), PetscDSGetBdJacobian()
2090 @*/
2091 PetscErrorCode PetscDSHasBdJacobian(PetscDS prob, PetscBool *hasBdJac)
2092 {
2093   PetscInt f, g, h;
2094 
2095   PetscFunctionBegin;
2096   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2097   *hasBdJac = PETSC_FALSE;
2098   for (f = 0; f < prob->Nf; ++f) {
2099     for (g = 0; g < prob->Nf; ++g) {
2100       for (h = 0; h < 4; ++h) {
2101         if (prob->gBd[(f*prob->Nf + g)*4+h]) *hasBdJac = PETSC_TRUE;
2102       }
2103     }
2104   }
2105   PetscFunctionReturn(0);
2106 }
2107 
2108 /*@C
2109   PetscDSGetBdJacobian - Get the pointwise boundary Jacobian function for given test and basis field
2110 
2111   Not collective
2112 
2113   Input Parameters:
2114 + prob - The PetscDS
2115 . f    - The test field number
2116 - g    - The field number
2117 
2118   Output Parameters:
2119 + g0 - integrand for the test and basis function term
2120 . g1 - integrand for the test function and basis function gradient term
2121 . g2 - integrand for the test function gradient and basis function term
2122 - g3 - integrand for the test function gradient and basis function gradient term
2123 
2124   Note: We are using a first order FEM model for the weak form:
2125 
2126   \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
2127 
2128 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2129 
2130 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2131 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2132 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2133 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])
2134 
2135 + dim - the spatial dimension
2136 . Nf - the number of fields
2137 . uOff - the offset into u[] and u_t[] for each field
2138 . uOff_x - the offset into u_x[] for each field
2139 . u - each field evaluated at the current point
2140 . u_t - the time derivative of each field evaluated at the current point
2141 . u_x - the gradient of each field evaluated at the current point
2142 . aOff - the offset into a[] and a_t[] for each auxiliary field
2143 . aOff_x - the offset into a_x[] for each auxiliary field
2144 . a - each auxiliary field evaluated at the current point
2145 . a_t - the time derivative of each auxiliary field evaluated at the current point
2146 . a_x - the gradient of auxiliary each field evaluated at the current point
2147 . t - current time
2148 . u_tShift - the multiplier a for dF/dU_t
2149 . x - coordinates of the current point
2150 . n - normal at the current point
2151 . numConstants - number of constant parameters
2152 . constants - constant parameters
2153 - g0 - output values at the current point
2154 
2155   Level: intermediate
2156 
2157 .seealso: PetscDSSetBdJacobian()
2158 @*/
2159 PetscErrorCode PetscDSGetBdJacobian(PetscDS prob, PetscInt f, PetscInt g,
2160                                     void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2161                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2162                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2163                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2164                                     void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2165                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2166                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2167                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2168                                     void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2169                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2170                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2171                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2172                                     void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2173                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2174                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2175                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2176 {
2177   PetscFunctionBegin;
2178   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2179   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);
2180   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);
2181   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gBd[(f*prob->Nf + g)*4+0];}
2182   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gBd[(f*prob->Nf + g)*4+1];}
2183   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gBd[(f*prob->Nf + g)*4+2];}
2184   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gBd[(f*prob->Nf + g)*4+3];}
2185   PetscFunctionReturn(0);
2186 }
2187 
2188 /*@C
2189   PetscDSSetBdJacobian - Set the pointwise boundary Jacobian function for given test and basis field
2190 
2191   Not collective
2192 
2193   Input Parameters:
2194 + prob - The PetscDS
2195 . f    - The test field number
2196 . g    - The field number
2197 . g0 - integrand for the test and basis function term
2198 . g1 - integrand for the test function and basis function gradient term
2199 . g2 - integrand for the test function gradient and basis function term
2200 - g3 - integrand for the test function gradient and basis function gradient term
2201 
2202   Note: We are using a first order FEM model for the weak form:
2203 
2204   \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
2205 
2206 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2207 
2208 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2209 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2210 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2211 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])
2212 
2213 + dim - the spatial dimension
2214 . Nf - the number of fields
2215 . uOff - the offset into u[] and u_t[] for each field
2216 . uOff_x - the offset into u_x[] for each field
2217 . u - each field evaluated at the current point
2218 . u_t - the time derivative of each field evaluated at the current point
2219 . u_x - the gradient of each field evaluated at the current point
2220 . aOff - the offset into a[] and a_t[] for each auxiliary field
2221 . aOff_x - the offset into a_x[] for each auxiliary field
2222 . a - each auxiliary field evaluated at the current point
2223 . a_t - the time derivative of each auxiliary field evaluated at the current point
2224 . a_x - the gradient of auxiliary each field evaluated at the current point
2225 . t - current time
2226 . u_tShift - the multiplier a for dF/dU_t
2227 . x - coordinates of the current point
2228 . n - normal at the current point
2229 . numConstants - number of constant parameters
2230 . constants - constant parameters
2231 - g0 - output values at the current point
2232 
2233   Level: intermediate
2234 
2235 .seealso: PetscDSGetBdJacobian()
2236 @*/
2237 PetscErrorCode PetscDSSetBdJacobian(PetscDS prob, PetscInt f, PetscInt g,
2238                                     void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2239                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2240                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2241                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2242                                     void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2243                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2244                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2245                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2246                                     void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2247                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2248                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2249                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2250                                     void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2251                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2252                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2253                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2254 {
2255   PetscErrorCode ierr;
2256 
2257   PetscFunctionBegin;
2258   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2259   if (g0) PetscValidFunction(g0, 4);
2260   if (g1) PetscValidFunction(g1, 5);
2261   if (g2) PetscValidFunction(g2, 6);
2262   if (g3) PetscValidFunction(g3, 7);
2263   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2264   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
2265   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
2266   prob->gBd[(f*prob->Nf + g)*4+0] = g0;
2267   prob->gBd[(f*prob->Nf + g)*4+1] = g1;
2268   prob->gBd[(f*prob->Nf + g)*4+2] = g2;
2269   prob->gBd[(f*prob->Nf + g)*4+3] = g3;
2270   PetscFunctionReturn(0);
2271 }
2272 
2273 /*@
2274   PetscDSHasBdJacobianPreconditioner - Signals that boundary Jacobian preconditioner functions have been set
2275 
2276   Not collective
2277 
2278   Input Parameter:
2279 . prob - The PetscDS
2280 
2281   Output Parameter:
2282 . hasBdJac - flag that pointwise function for the boundary Jacobian preconditioner has been set
2283 
2284   Level: intermediate
2285 
2286 .seealso: PetscDSHasJacobian(), PetscDSSetBdJacobian(), PetscDSGetBdJacobian()
2287 @*/
2288 PetscErrorCode PetscDSHasBdJacobianPreconditioner(PetscDS prob, PetscBool *hasBdJacPre)
2289 {
2290   PetscInt f, g, h;
2291 
2292   PetscFunctionBegin;
2293   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2294   *hasBdJacPre = PETSC_FALSE;
2295   for (f = 0; f < prob->Nf; ++f) {
2296     for (g = 0; g < prob->Nf; ++g) {
2297       for (h = 0; h < 4; ++h) {
2298         if (prob->gpBd[(f*prob->Nf + g)*4+h]) *hasBdJacPre = PETSC_TRUE;
2299       }
2300     }
2301   }
2302   PetscFunctionReturn(0);
2303 }
2304 
2305 /*@C
2306   PetscDSGetBdJacobianPreconditioner - Get the pointwise boundary Jacobian preconditioner function for given test and basis field
2307 
2308   Not collective
2309 
2310   Input Parameters:
2311 + prob - The PetscDS
2312 . f    - The test field number
2313 - g    - The field number
2314 
2315   Output Parameters:
2316 + g0 - integrand for the test and basis function term
2317 . g1 - integrand for the test function and basis function gradient term
2318 . g2 - integrand for the test function gradient and basis function term
2319 - g3 - integrand for the test function gradient and basis function gradient term
2320 
2321   Note: We are using a first order FEM model for the weak form:
2322 
2323   \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
2324 
2325 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2326 
2327 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2328 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2329 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2330 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
2331 
2332 + dim - the spatial dimension
2333 . Nf - the number of fields
2334 . NfAux - the number of auxiliary fields
2335 . uOff - the offset into u[] and u_t[] for each field
2336 . uOff_x - the offset into u_x[] for each field
2337 . u - each field evaluated at the current point
2338 . u_t - the time derivative of each field evaluated at the current point
2339 . u_x - the gradient of each field evaluated at the current point
2340 . aOff - the offset into a[] and a_t[] for each auxiliary field
2341 . aOff_x - the offset into a_x[] for each auxiliary field
2342 . a - each auxiliary field evaluated at the current point
2343 . a_t - the time derivative of each auxiliary field evaluated at the current point
2344 . a_x - the gradient of auxiliary each field evaluated at the current point
2345 . t - current time
2346 . u_tShift - the multiplier a for dF/dU_t
2347 . x - coordinates of the current point
2348 . n - normal at the current point
2349 . numConstants - number of constant parameters
2350 . constants - constant parameters
2351 - g0 - output values at the current point
2352 
2353   This is not yet available in Fortran.
2354 
2355   Level: intermediate
2356 
2357 .seealso: PetscDSSetBdJacobianPreconditioner()
2358 @*/
2359 PetscErrorCode PetscDSGetBdJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
2360                                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2361                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2362                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2363                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2364                                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2365                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2366                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2367                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2368                                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2369                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2370                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2371                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2372                                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2373                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2374                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2375                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2376 {
2377   PetscFunctionBegin;
2378   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2379   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);
2380   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);
2381   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gpBd[(f*prob->Nf + g)*4+0];}
2382   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gpBd[(f*prob->Nf + g)*4+1];}
2383   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gpBd[(f*prob->Nf + g)*4+2];}
2384   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gpBd[(f*prob->Nf + g)*4+3];}
2385   PetscFunctionReturn(0);
2386 }
2387 
2388 /*@C
2389   PetscDSSetBdJacobianPreconditioner - Set the pointwise boundary Jacobian preconditioner function for given test and basis field
2390 
2391   Not collective
2392 
2393   Input Parameters:
2394 + prob - The PetscDS
2395 . f    - The test field number
2396 . g    - The field number
2397 . g0 - integrand for the test and basis function term
2398 . g1 - integrand for the test function and basis function gradient term
2399 . g2 - integrand for the test function gradient and basis function term
2400 - g3 - integrand for the test function gradient and basis function gradient term
2401 
2402   Note: We are using a first order FEM model for the weak form:
2403 
2404   \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
2405 
2406 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2407 
2408 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2409 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2410 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2411 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
2412 
2413 + dim - the spatial dimension
2414 . Nf - the number of fields
2415 . NfAux - the number of auxiliary fields
2416 . uOff - the offset into u[] and u_t[] for each field
2417 . uOff_x - the offset into u_x[] for each field
2418 . u - each field evaluated at the current point
2419 . u_t - the time derivative of each field evaluated at the current point
2420 . u_x - the gradient of each field evaluated at the current point
2421 . aOff - the offset into a[] and a_t[] for each auxiliary field
2422 . aOff_x - the offset into a_x[] for each auxiliary field
2423 . a - each auxiliary field evaluated at the current point
2424 . a_t - the time derivative of each auxiliary field evaluated at the current point
2425 . a_x - the gradient of auxiliary each field evaluated at the current point
2426 . t - current time
2427 . u_tShift - the multiplier a for dF/dU_t
2428 . x - coordinates of the current point
2429 . n - normal at the current point
2430 . numConstants - number of constant parameters
2431 . constants - constant parameters
2432 - g0 - output values at the current point
2433 
2434   This is not yet available in Fortran.
2435 
2436   Level: intermediate
2437 
2438 .seealso: PetscDSGetBdJacobianPreconditioner()
2439 @*/
2440 PetscErrorCode PetscDSSetBdJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
2441                                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2442                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2443                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2444                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2445                                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2446                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2447                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2448                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2449                                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2450                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2451                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2452                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2453                                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2454                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2455                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2456                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2457 {
2458   PetscErrorCode ierr;
2459 
2460   PetscFunctionBegin;
2461   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2462   if (g0) PetscValidFunction(g0, 4);
2463   if (g1) PetscValidFunction(g1, 5);
2464   if (g2) PetscValidFunction(g2, 6);
2465   if (g3) PetscValidFunction(g3, 7);
2466   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2467   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
2468   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
2469   prob->gpBd[(f*prob->Nf + g)*4+0] = g0;
2470   prob->gpBd[(f*prob->Nf + g)*4+1] = g1;
2471   prob->gpBd[(f*prob->Nf + g)*4+2] = g2;
2472   prob->gpBd[(f*prob->Nf + g)*4+3] = g3;
2473   PetscFunctionReturn(0);
2474 }
2475 
2476 /*@C
2477   PetscDSGetExactSolution - Get the pointwise exact solution function for a given test field
2478 
2479   Not collective
2480 
2481   Input Parameters:
2482 + prob - The PetscDS
2483 - f    - The test field number
2484 
2485   Output Parameter:
2486 + exactSol - exact solution for the test field
2487 - exactCtx - exact solution context
2488 
2489   Note: The calling sequence for the solution functions is given by:
2490 
2491 $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2492 
2493 + dim - the spatial dimension
2494 . t - current time
2495 . x - coordinates of the current point
2496 . Nc - the number of field components
2497 . u - the solution field evaluated at the current point
2498 - ctx - a user context
2499 
2500   Level: intermediate
2501 
2502 .seealso: PetscDSSetExactSolution()
2503 @*/
2504 PetscErrorCode PetscDSGetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
2505 {
2506   PetscFunctionBegin;
2507   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2508   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);
2509   if (sol) {PetscValidPointer(sol, 3); *sol = prob->exactSol[f];}
2510   if (ctx) {PetscValidPointer(ctx, 4); *ctx = prob->exactCtx[f];}
2511   PetscFunctionReturn(0);
2512 }
2513 
2514 /*@C
2515   PetscDSSetExactSolution - Set the pointwise exact solution function for a given test field
2516 
2517   Not collective
2518 
2519   Input Parameters:
2520 + prob - The PetscDS
2521 . f    - The test field number
2522 . sol  - solution function for the test fields
2523 - ctx  - solution context or NULL
2524 
2525   Note: The calling sequence for solution functions is given by:
2526 
2527 $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2528 
2529 + dim - the spatial dimension
2530 . t - current time
2531 . x - coordinates of the current point
2532 . Nc - the number of field components
2533 . u - the solution field evaluated at the current point
2534 - ctx - a user context
2535 
2536   Level: intermediate
2537 
2538 .seealso: PetscDSGetExactSolution()
2539 @*/
2540 PetscErrorCode PetscDSSetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
2541 {
2542   PetscErrorCode ierr;
2543 
2544   PetscFunctionBegin;
2545   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2546   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2547   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
2548   if (sol) {PetscValidFunction(sol, 3); prob->exactSol[f] = sol;}
2549   if (ctx) {PetscValidFunction(ctx, 4); prob->exactCtx[f] = ctx;}
2550   PetscFunctionReturn(0);
2551 }
2552 
2553 /*@C
2554   PetscDSGetConstants - Returns the array of constants passed to point functions
2555 
2556   Not collective
2557 
2558   Input Parameter:
2559 . prob - The PetscDS object
2560 
2561   Output Parameters:
2562 + numConstants - The number of constants
2563 - constants    - The array of constants, NULL if there are none
2564 
2565   Level: intermediate
2566 
2567 .seealso: PetscDSSetConstants(), PetscDSCreate()
2568 @*/
2569 PetscErrorCode PetscDSGetConstants(PetscDS prob, PetscInt *numConstants, const PetscScalar *constants[])
2570 {
2571   PetscFunctionBegin;
2572   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2573   if (numConstants) {PetscValidPointer(numConstants, 2); *numConstants = prob->numConstants;}
2574   if (constants)    {PetscValidPointer(constants, 3);    *constants    = prob->constants;}
2575   PetscFunctionReturn(0);
2576 }
2577 
2578 /*@C
2579   PetscDSSetConstants - Set the array of constants passed to point functions
2580 
2581   Not collective
2582 
2583   Input Parameters:
2584 + prob         - The PetscDS object
2585 . numConstants - The number of constants
2586 - constants    - The array of constants, NULL if there are none
2587 
2588   Level: intermediate
2589 
2590 .seealso: PetscDSGetConstants(), PetscDSCreate()
2591 @*/
2592 PetscErrorCode PetscDSSetConstants(PetscDS prob, PetscInt numConstants, PetscScalar constants[])
2593 {
2594   PetscErrorCode ierr;
2595 
2596   PetscFunctionBegin;
2597   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2598   if (numConstants != prob->numConstants) {
2599     ierr = PetscFree(prob->constants);CHKERRQ(ierr);
2600     prob->numConstants = numConstants;
2601     if (prob->numConstants) {
2602       ierr = PetscMalloc1(prob->numConstants, &prob->constants);CHKERRQ(ierr);
2603     } else {
2604       prob->constants = NULL;
2605     }
2606   }
2607   if (prob->numConstants) {
2608     PetscValidPointer(constants, 3);
2609     ierr = PetscArraycpy(prob->constants, constants, prob->numConstants);CHKERRQ(ierr);
2610   }
2611   PetscFunctionReturn(0);
2612 }
2613 
2614 /*@
2615   PetscDSGetFieldIndex - Returns the index of the given field
2616 
2617   Not collective
2618 
2619   Input Parameters:
2620 + prob - The PetscDS object
2621 - disc - The discretization object
2622 
2623   Output Parameter:
2624 . f - The field number
2625 
2626   Level: beginner
2627 
2628 .seealso: PetscGetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
2629 @*/
2630 PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
2631 {
2632   PetscInt g;
2633 
2634   PetscFunctionBegin;
2635   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2636   PetscValidPointer(f, 3);
2637   *f = -1;
2638   for (g = 0; g < prob->Nf; ++g) {if (disc == prob->disc[g]) break;}
2639   if (g == prob->Nf) SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
2640   *f = g;
2641   PetscFunctionReturn(0);
2642 }
2643 
2644 /*@
2645   PetscDSGetFieldSize - Returns the size of the given field in the full space basis
2646 
2647   Not collective
2648 
2649   Input Parameters:
2650 + prob - The PetscDS object
2651 - f - The field number
2652 
2653   Output Parameter:
2654 . size - The size
2655 
2656   Level: beginner
2657 
2658 .seealso: PetscDSGetFieldOffset(), PetscDSGetNumFields(), PetscDSCreate()
2659 @*/
2660 PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
2661 {
2662   PetscErrorCode ierr;
2663 
2664   PetscFunctionBegin;
2665   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2666   PetscValidPointer(size, 3);
2667   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);
2668   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2669   *size = prob->Nb[f];
2670   PetscFunctionReturn(0);
2671 }
2672 
2673 /*@
2674   PetscDSGetFieldOffset - Returns the offset of the given field in the full space basis
2675 
2676   Not collective
2677 
2678   Input Parameters:
2679 + prob - The PetscDS object
2680 - f - The field number
2681 
2682   Output Parameter:
2683 . off - The offset
2684 
2685   Level: beginner
2686 
2687 .seealso: PetscDSGetFieldSize(), PetscDSGetNumFields(), PetscDSCreate()
2688 @*/
2689 PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
2690 {
2691   PetscInt       size, g;
2692   PetscErrorCode ierr;
2693 
2694   PetscFunctionBegin;
2695   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2696   PetscValidPointer(off, 3);
2697   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);
2698   *off = 0;
2699   for (g = 0; g < f; ++g) {
2700     ierr = PetscDSGetFieldSize(prob, g, &size);CHKERRQ(ierr);
2701     *off += size;
2702   }
2703   PetscFunctionReturn(0);
2704 }
2705 
2706 /*@
2707   PetscDSGetDimensions - Returns the size of the approximation space for each field on an evaluation point
2708 
2709   Not collective
2710 
2711   Input Parameter:
2712 . prob - The PetscDS object
2713 
2714   Output Parameter:
2715 . dimensions - The number of dimensions
2716 
2717   Level: beginner
2718 
2719 .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
2720 @*/
2721 PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
2722 {
2723   PetscErrorCode ierr;
2724 
2725   PetscFunctionBegin;
2726   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2727   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2728   PetscValidPointer(dimensions, 2);
2729   *dimensions = prob->Nb;
2730   PetscFunctionReturn(0);
2731 }
2732 
2733 /*@
2734   PetscDSGetComponents - Returns the number of components for each field on an evaluation point
2735 
2736   Not collective
2737 
2738   Input Parameter:
2739 . prob - The PetscDS object
2740 
2741   Output Parameter:
2742 . components - The number of components
2743 
2744   Level: beginner
2745 
2746 .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
2747 @*/
2748 PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
2749 {
2750   PetscErrorCode ierr;
2751 
2752   PetscFunctionBegin;
2753   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2754   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2755   PetscValidPointer(components, 2);
2756   *components = prob->Nc;
2757   PetscFunctionReturn(0);
2758 }
2759 
2760 /*@
2761   PetscDSGetComponentOffset - Returns the offset of the given field on an evaluation point
2762 
2763   Not collective
2764 
2765   Input Parameters:
2766 + prob - The PetscDS object
2767 - f - The field number
2768 
2769   Output Parameter:
2770 . off - The offset
2771 
2772   Level: beginner
2773 
2774 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2775 @*/
2776 PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
2777 {
2778   PetscFunctionBegin;
2779   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2780   PetscValidPointer(off, 3);
2781   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);
2782   *off = prob->off[f];
2783   PetscFunctionReturn(0);
2784 }
2785 
2786 /*@
2787   PetscDSGetComponentOffsets - Returns the offset of each field on an evaluation point
2788 
2789   Not collective
2790 
2791   Input Parameter:
2792 . prob - The PetscDS object
2793 
2794   Output Parameter:
2795 . offsets - The offsets
2796 
2797   Level: beginner
2798 
2799 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2800 @*/
2801 PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
2802 {
2803   PetscFunctionBegin;
2804   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2805   PetscValidPointer(offsets, 2);
2806   *offsets = prob->off;
2807   PetscFunctionReturn(0);
2808 }
2809 
2810 /*@
2811   PetscDSGetComponentDerivativeOffsets - Returns the offset of each field derivative on an evaluation point
2812 
2813   Not collective
2814 
2815   Input Parameter:
2816 . prob - The PetscDS object
2817 
2818   Output Parameter:
2819 . offsets - The offsets
2820 
2821   Level: beginner
2822 
2823 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2824 @*/
2825 PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
2826 {
2827   PetscFunctionBegin;
2828   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2829   PetscValidPointer(offsets, 2);
2830   *offsets = prob->offDer;
2831   PetscFunctionReturn(0);
2832 }
2833 
2834 /*@C
2835   PetscDSGetTabulation - Return the basis tabulation at quadrature points for the volume discretization
2836 
2837   Not collective
2838 
2839   Input Parameter:
2840 . prob - The PetscDS object
2841 
2842   Output Parameter:
2843 . T - The basis function and derivatives tabulation at quadrature points for each field
2844 
2845   Level: intermediate
2846 
2847 .seealso: PetscDSCreate()
2848 @*/
2849 PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[])
2850 {
2851   PetscErrorCode ierr;
2852 
2853   PetscFunctionBegin;
2854   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2855   PetscValidPointer(T, 2);
2856   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2857   *T = prob->T;
2858   PetscFunctionReturn(0);
2859 }
2860 
2861 /*@C
2862   PetscDSGetFaceTabulation - Return the basis tabulation at quadrature points on the faces
2863 
2864   Not collective
2865 
2866   Input Parameter:
2867 . prob - The PetscDS object
2868 
2869   Output Parameter:
2870 . Tf - The basis function and derviative tabulation on each lcoal face at quadrature points for each and field
2871 
2872   Level: intermediate
2873 
2874 .seealso: PetscDSGetTabulation(), PetscDSCreate()
2875 @*/
2876 PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
2877 {
2878   PetscErrorCode ierr;
2879 
2880   PetscFunctionBegin;
2881   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2882   PetscValidPointer(Tf, 2);
2883   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2884   *Tf = prob->Tf;
2885   PetscFunctionReturn(0);
2886 }
2887 
2888 PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
2889 {
2890   PetscErrorCode ierr;
2891 
2892   PetscFunctionBegin;
2893   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2894   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2895   if (u)   {PetscValidPointer(u, 2);   *u   = prob->u;}
2896   if (u_t) {PetscValidPointer(u_t, 3); *u_t = prob->u_t;}
2897   if (u_x) {PetscValidPointer(u_x, 4); *u_x = prob->u_x;}
2898   PetscFunctionReturn(0);
2899 }
2900 
2901 PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar **f0, PetscScalar **f1, PetscScalar **g0, PetscScalar **g1, PetscScalar **g2, PetscScalar **g3)
2902 {
2903   PetscErrorCode ierr;
2904 
2905   PetscFunctionBegin;
2906   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2907   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2908   if (f0) {PetscValidPointer(f0, 2); *f0 = prob->f0;}
2909   if (f1) {PetscValidPointer(f1, 3); *f1 = prob->f1;}
2910   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->g0;}
2911   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->g1;}
2912   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->g2;}
2913   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->g3;}
2914   PetscFunctionReturn(0);
2915 }
2916 
2917 PetscErrorCode PetscDSGetWorkspace(PetscDS prob, PetscReal **x, PetscScalar **basisReal, PetscScalar **basisDerReal, PetscScalar **testReal, PetscScalar **testDerReal)
2918 {
2919   PetscErrorCode ierr;
2920 
2921   PetscFunctionBegin;
2922   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2923   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2924   if (x)            {PetscValidPointer(x, 2);            *x            = prob->x;}
2925   if (basisReal)    {PetscValidPointer(basisReal, 3);    *basisReal    = prob->basisReal;}
2926   if (basisDerReal) {PetscValidPointer(basisDerReal, 4); *basisDerReal = prob->basisDerReal;}
2927   if (testReal)     {PetscValidPointer(testReal, 5);     *testReal     = prob->testReal;}
2928   if (testDerReal)  {PetscValidPointer(testDerReal, 6);  *testDerReal  = prob->testDerReal;}
2929   PetscFunctionReturn(0);
2930 }
2931 
2932 /*@C
2933   PetscDSAddBoundary - Add a boundary condition to the model
2934 
2935   Collective on ds
2936 
2937   Input Parameters:
2938 + ds          - The PetscDS object
2939 . type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
2940 . name        - The BC name
2941 . labelname   - The label defining constrained points
2942 . field       - The field to constrain
2943 . numcomps    - The number of constrained field components (0 will constrain all fields)
2944 . comps       - An array of constrained component numbers
2945 . bcFunc      - A pointwise function giving boundary values
2946 . numids      - The number of DMLabel ids for constrained points
2947 . ids         - An array of ids for constrained points
2948 - ctx         - An optional user context for bcFunc
2949 
2950   Options Database Keys:
2951 + -bc_<boundary name> <num> - Overrides the boundary ids
2952 - -bc_<boundary name>_comp <num> - Overrides the boundary components
2953 
2954   Level: developer
2955 
2956 .seealso: PetscDSGetBoundary()
2957 @*/
2958 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)
2959 {
2960   DSBoundary     b;
2961   PetscErrorCode ierr;
2962 
2963   PetscFunctionBegin;
2964   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2965   PetscValidLogicalCollectiveEnum(ds, type, 2);
2966   PetscValidLogicalCollectiveInt(ds, field, 5);
2967   PetscValidLogicalCollectiveInt(ds, numcomps, 6);
2968   PetscValidLogicalCollectiveInt(ds, numids, 9);
2969   ierr = PetscNew(&b);CHKERRQ(ierr);
2970   ierr = PetscStrallocpy(name, (char **) &b->name);CHKERRQ(ierr);
2971   ierr = PetscStrallocpy(labelname, (char **) &b->labelname);CHKERRQ(ierr);
2972   ierr = PetscMalloc1(numcomps, &b->comps);CHKERRQ(ierr);
2973   if (numcomps) {ierr = PetscArraycpy(b->comps, comps, numcomps);CHKERRQ(ierr);}
2974   ierr = PetscMalloc1(numids, &b->ids);CHKERRQ(ierr);
2975   if (numids) {ierr = PetscArraycpy(b->ids, ids, numids);CHKERRQ(ierr);}
2976   b->type            = type;
2977   b->field           = field;
2978   b->numcomps        = numcomps;
2979   b->func            = bcFunc;
2980   b->numids          = numids;
2981   b->ctx             = ctx;
2982   b->next            = ds->boundary;
2983   ds->boundary       = b;
2984   PetscFunctionReturn(0);
2985 }
2986 
2987 /*@C
2988   PetscDSUpdateBoundary - Change a boundary condition for the model
2989 
2990   Input Parameters:
2991 + ds          - The PetscDS object
2992 . bd          - The boundary condition number
2993 . type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
2994 . name        - The BC name
2995 . labelname   - The label defining constrained points
2996 . field       - The field to constrain
2997 . numcomps    - The number of constrained field components
2998 . comps       - An array of constrained component numbers
2999 . bcFunc      - A pointwise function giving boundary values
3000 . numids      - The number of DMLabel ids for constrained points
3001 . ids         - An array of ids for constrained points
3002 - ctx         - An optional user context for bcFunc
3003 
3004   Note: The boundary condition number is the order in which it was registered. The user can get the number of boundary conditions from PetscDSGetNumBoundary().
3005 
3006   Level: developer
3007 
3008 .seealso: PetscDSAddBoundary(), PetscDSGetBoundary(), PetscDSGetNumBoundary()
3009 @*/
3010 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)
3011 {
3012   DSBoundary     b = ds->boundary;
3013   PetscInt       n = 0;
3014   PetscErrorCode ierr;
3015 
3016   PetscFunctionBegin;
3017   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3018   while (b) {
3019     if (n == bd) break;
3020     b = b->next;
3021     ++n;
3022   }
3023   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
3024   if (name) {
3025     ierr = PetscFree(b->name);CHKERRQ(ierr);
3026     ierr = PetscStrallocpy(name, (char **) &b->name);CHKERRQ(ierr);
3027   }
3028   if (labelname) {
3029     ierr = PetscFree(b->labelname);CHKERRQ(ierr);
3030     ierr = PetscStrallocpy(labelname, (char **) &b->labelname);CHKERRQ(ierr);
3031   }
3032   if (numcomps >= 0 && numcomps != b->numcomps) {
3033     b->numcomps = numcomps;
3034     ierr = PetscFree(b->comps);CHKERRQ(ierr);
3035     ierr = PetscMalloc1(numcomps, &b->comps);CHKERRQ(ierr);
3036     if (numcomps) {ierr = PetscArraycpy(b->comps, comps, numcomps);CHKERRQ(ierr);}
3037   }
3038   if (numids >= 0 && numids != b->numids) {
3039     b->numids = numids;
3040     ierr = PetscFree(b->ids);CHKERRQ(ierr);
3041     ierr = PetscMalloc1(numids, &b->ids);CHKERRQ(ierr);
3042     if (numids) {ierr = PetscArraycpy(b->ids, ids, numids);CHKERRQ(ierr);}
3043   }
3044   b->type = type;
3045   if (field >= 0) {b->field  = field;}
3046   if (bcFunc)     {b->func   = bcFunc;}
3047   if (ctx)        {b->ctx    = ctx;}
3048   PetscFunctionReturn(0);
3049 }
3050 
3051 /*@
3052   PetscDSGetNumBoundary - Get the number of registered BC
3053 
3054   Input Parameters:
3055 . ds - The PetscDS object
3056 
3057   Output Parameters:
3058 . numBd - The number of BC
3059 
3060   Level: intermediate
3061 
3062 .seealso: PetscDSAddBoundary(), PetscDSGetBoundary()
3063 @*/
3064 PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
3065 {
3066   DSBoundary b = ds->boundary;
3067 
3068   PetscFunctionBegin;
3069   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3070   PetscValidPointer(numBd, 2);
3071   *numBd = 0;
3072   while (b) {++(*numBd); b = b->next;}
3073   PetscFunctionReturn(0);
3074 }
3075 
3076 /*@C
3077   PetscDSGetBoundary - Gets a boundary condition to the model
3078 
3079   Input Parameters:
3080 + ds          - The PetscDS object
3081 - bd          - The BC number
3082 
3083   Output Parameters:
3084 + type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
3085 . name        - The BC name
3086 . labelname   - The label defining constrained points
3087 . field       - The field to constrain
3088 . numcomps    - The number of constrained field components
3089 . comps       - An array of constrained component numbers
3090 . bcFunc      - A pointwise function giving boundary values
3091 . numids      - The number of DMLabel ids for constrained points
3092 . ids         - An array of ids for constrained points
3093 - ctx         - An optional user context for bcFunc
3094 
3095   Options Database Keys:
3096 + -bc_<boundary name> <num> - Overrides the boundary ids
3097 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3098 
3099   Level: developer
3100 
3101 .seealso: PetscDSAddBoundary()
3102 @*/
3103 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)
3104 {
3105   DSBoundary b    = ds->boundary;
3106   PetscInt   n    = 0;
3107 
3108   PetscFunctionBegin;
3109   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3110   while (b) {
3111     if (n == bd) break;
3112     b = b->next;
3113     ++n;
3114   }
3115   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
3116   if (type) {
3117     PetscValidPointer(type, 3);
3118     *type = b->type;
3119   }
3120   if (name) {
3121     PetscValidPointer(name, 4);
3122     *name = b->name;
3123   }
3124   if (labelname) {
3125     PetscValidPointer(labelname, 5);
3126     *labelname = b->labelname;
3127   }
3128   if (field) {
3129     PetscValidPointer(field, 6);
3130     *field = b->field;
3131   }
3132   if (numcomps) {
3133     PetscValidPointer(numcomps, 7);
3134     *numcomps = b->numcomps;
3135   }
3136   if (comps) {
3137     PetscValidPointer(comps, 8);
3138     *comps = b->comps;
3139   }
3140   if (func) {
3141     PetscValidPointer(func, 9);
3142     *func = b->func;
3143   }
3144   if (numids) {
3145     PetscValidPointer(numids, 10);
3146     *numids = b->numids;
3147   }
3148   if (ids) {
3149     PetscValidPointer(ids, 11);
3150     *ids = b->ids;
3151   }
3152   if (ctx) {
3153     PetscValidPointer(ctx, 12);
3154     *ctx = b->ctx;
3155   }
3156   PetscFunctionReturn(0);
3157 }
3158 
3159 /*@
3160   PetscDSCopyBoundary - Copy all boundary condition objects to the new problem
3161 
3162   Not collective
3163 
3164   Input Parameter:
3165 . prob - The PetscDS object
3166 
3167   Output Parameter:
3168 . newprob - The PetscDS copy
3169 
3170   Level: intermediate
3171 
3172 .seealso: PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3173 @*/
3174 PetscErrorCode PetscDSCopyBoundary(PetscDS probA, PetscDS probB)
3175 {
3176   DSBoundary     b, next, *lastnext;
3177   PetscErrorCode ierr;
3178 
3179   PetscFunctionBegin;
3180   PetscValidHeaderSpecific(probA, PETSCDS_CLASSID, 1);
3181   PetscValidHeaderSpecific(probB, PETSCDS_CLASSID, 2);
3182   if (probA == probB) PetscFunctionReturn(0);
3183   next = probB->boundary;
3184   while (next) {
3185     DSBoundary b = next;
3186 
3187     next = b->next;
3188     ierr = PetscFree(b->comps);CHKERRQ(ierr);
3189     ierr = PetscFree(b->ids);CHKERRQ(ierr);
3190     ierr = PetscFree(b->name);CHKERRQ(ierr);
3191     ierr = PetscFree(b->labelname);CHKERRQ(ierr);
3192     ierr = PetscFree(b);CHKERRQ(ierr);
3193   }
3194   lastnext = &(probB->boundary);
3195   for (b = probA->boundary; b; b = b->next) {
3196     DSBoundary bNew;
3197 
3198     ierr = PetscNew(&bNew);CHKERRQ(ierr);
3199     bNew->numcomps = b->numcomps;
3200     ierr = PetscMalloc1(bNew->numcomps, &bNew->comps);CHKERRQ(ierr);
3201     ierr = PetscArraycpy(bNew->comps, b->comps, bNew->numcomps);CHKERRQ(ierr);
3202     bNew->numids = b->numids;
3203     ierr = PetscMalloc1(bNew->numids, &bNew->ids);CHKERRQ(ierr);
3204     ierr = PetscArraycpy(bNew->ids, b->ids, bNew->numids);CHKERRQ(ierr);
3205     ierr = PetscStrallocpy(b->labelname,(char **) &(bNew->labelname));CHKERRQ(ierr);
3206     ierr = PetscStrallocpy(b->name,(char **) &(bNew->name));CHKERRQ(ierr);
3207     bNew->ctx   = b->ctx;
3208     bNew->type  = b->type;
3209     bNew->field = b->field;
3210     bNew->func  = b->func;
3211 
3212     *lastnext = bNew;
3213     lastnext = &(bNew->next);
3214   }
3215   PetscFunctionReturn(0);
3216 }
3217 
3218 /*@C
3219   PetscDSSelectEquations - Copy pointwise function pointers to the new problem with different field layout
3220 
3221   Not collective
3222 
3223   Input Parameter:
3224 + prob - The PetscDS object
3225 . numFields - Number of new fields
3226 - fields - Old field number for each new field
3227 
3228   Output Parameter:
3229 . newprob - The PetscDS copy
3230 
3231   Level: intermediate
3232 
3233 .seealso: PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3234 @*/
3235 PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
3236 {
3237   PetscInt       Nf, Nfn, fn, gn;
3238   PetscErrorCode ierr;
3239 
3240   PetscFunctionBegin;
3241   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3242   if (fields) PetscValidPointer(fields, 3);
3243   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 4);
3244   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
3245   ierr = PetscDSGetNumFields(newprob, &Nfn);CHKERRQ(ierr);
3246   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);
3247   for (fn = 0; fn < numFields; ++fn) {
3248     const PetscInt   f = fields ? fields[fn] : fn;
3249     PetscPointFunc   obj;
3250     PetscPointFunc   f0, f1;
3251     PetscBdPointFunc f0Bd, f1Bd;
3252     PetscRiemannFunc r;
3253 
3254     if (f >= Nf) continue;
3255     ierr = PetscDSGetObjective(prob, f, &obj);CHKERRQ(ierr);
3256     ierr = PetscDSGetResidual(prob, f, &f0, &f1);CHKERRQ(ierr);
3257     ierr = PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd);CHKERRQ(ierr);
3258     ierr = PetscDSGetRiemannSolver(prob, f, &r);CHKERRQ(ierr);
3259     ierr = PetscDSSetObjective(newprob, fn, obj);CHKERRQ(ierr);
3260     ierr = PetscDSSetResidual(newprob, fn, f0, f1);CHKERRQ(ierr);
3261     ierr = PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd);CHKERRQ(ierr);
3262     ierr = PetscDSSetRiemannSolver(newprob, fn, r);CHKERRQ(ierr);
3263     for (gn = 0; gn < numFields; ++gn) {
3264       const PetscInt  g = fields ? fields[gn] : gn;
3265       PetscPointJac   g0, g1, g2, g3;
3266       PetscPointJac   g0p, g1p, g2p, g3p;
3267       PetscBdPointJac g0Bd, g1Bd, g2Bd, g3Bd;
3268 
3269       if (g >= Nf) continue;
3270       ierr = PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3);CHKERRQ(ierr);
3271       ierr = PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p);CHKERRQ(ierr);
3272       ierr = PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd);CHKERRQ(ierr);
3273       ierr = PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3);CHKERRQ(ierr);
3274       ierr = PetscDSSetJacobianPreconditioner(prob, fn, gn, g0p, g1p, g2p, g3p);CHKERRQ(ierr);
3275       ierr = PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd);CHKERRQ(ierr);
3276     }
3277   }
3278   PetscFunctionReturn(0);
3279 }
3280 
3281 /*@
3282   PetscDSCopyEquations - Copy all pointwise function pointers to the new problem
3283 
3284   Not collective
3285 
3286   Input Parameter:
3287 . prob - The PetscDS object
3288 
3289   Output Parameter:
3290 . newprob - The PetscDS copy
3291 
3292   Level: intermediate
3293 
3294 .seealso: PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3295 @*/
3296 PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
3297 {
3298   PetscInt       Nf, Ng;
3299   PetscErrorCode ierr;
3300 
3301   PetscFunctionBegin;
3302   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3303   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
3304   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
3305   ierr = PetscDSGetNumFields(newprob, &Ng);CHKERRQ(ierr);
3306   if (Nf != Ng) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %D != %D", Nf, Ng);
3307   ierr = PetscDSSelectEquations(prob, Nf, NULL, newprob);CHKERRQ(ierr);
3308   PetscFunctionReturn(0);
3309 }
3310 /*@
3311   PetscDSCopyConstants - Copy all constants to the new problem
3312 
3313   Not collective
3314 
3315   Input Parameter:
3316 . prob - The PetscDS object
3317 
3318   Output Parameter:
3319 . newprob - The PetscDS copy
3320 
3321   Level: intermediate
3322 
3323 .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3324 @*/
3325 PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
3326 {
3327   PetscInt           Nc;
3328   const PetscScalar *constants;
3329   PetscErrorCode     ierr;
3330 
3331   PetscFunctionBegin;
3332   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3333   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
3334   ierr = PetscDSGetConstants(prob, &Nc, &constants);CHKERRQ(ierr);
3335   ierr = PetscDSSetConstants(newprob, Nc, (PetscScalar *) constants);CHKERRQ(ierr);
3336   PetscFunctionReturn(0);
3337 }
3338 
3339 PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
3340 {
3341   PetscInt       dim, Nf, f;
3342   PetscErrorCode ierr;
3343 
3344   PetscFunctionBegin;
3345   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3346   PetscValidPointer(subprob, 3);
3347   if (height == 0) {*subprob = prob; PetscFunctionReturn(0);}
3348   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
3349   ierr = PetscDSGetSpatialDimension(prob, &dim);CHKERRQ(ierr);
3350   if (height > dim) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %D], not %D", dim, height);
3351   if (!prob->subprobs) {ierr = PetscCalloc1(dim, &prob->subprobs);CHKERRQ(ierr);}
3352   if (!prob->subprobs[height-1]) {
3353     PetscInt cdim;
3354 
3355     ierr = PetscDSCreate(PetscObjectComm((PetscObject) prob), &prob->subprobs[height-1]);CHKERRQ(ierr);
3356     ierr = PetscDSGetCoordinateDimension(prob, &cdim);CHKERRQ(ierr);
3357     ierr = PetscDSSetCoordinateDimension(prob->subprobs[height-1], cdim);CHKERRQ(ierr);
3358     for (f = 0; f < Nf; ++f) {
3359       PetscFE      subfe;
3360       PetscObject  obj;
3361       PetscClassId id;
3362 
3363       ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
3364       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
3365       if (id == PETSCFE_CLASSID) {ierr = PetscFEGetHeightSubspace((PetscFE) obj, height, &subfe);CHKERRQ(ierr);}
3366       else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %d", f);
3367       ierr = PetscDSSetDiscretization(prob->subprobs[height-1], f, (PetscObject) subfe);CHKERRQ(ierr);
3368     }
3369   }
3370   *subprob = prob->subprobs[height-1];
3371   PetscFunctionReturn(0);
3372 }
3373 
3374 PetscErrorCode PetscDSGetDiscType_Internal(PetscDS ds, PetscInt f, PetscDiscType *disctype)
3375 {
3376   PetscObject    obj;
3377   PetscClassId   id;
3378   PetscInt       Nf;
3379   PetscErrorCode ierr;
3380 
3381   PetscFunctionBegin;
3382   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3383   PetscValidPointer(disctype, 3);
3384   *disctype = PETSC_DISC_NONE;
3385   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
3386   if (f >= Nf) SETERRQ2(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_SIZ, "Field %D must be in [0, %D)", f, Nf);
3387   ierr = PetscDSGetDiscretization(ds, f, &obj);CHKERRQ(ierr);
3388   if (obj) {
3389     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
3390     if (id == PETSCFE_CLASSID) *disctype = PETSC_DISC_FE;
3391     else                       *disctype = PETSC_DISC_FV;
3392   }
3393   PetscFunctionReturn(0);
3394 }
3395 
3396 static PetscErrorCode PetscDSDestroy_Basic(PetscDS prob)
3397 {
3398   PetscErrorCode      ierr;
3399 
3400   PetscFunctionBegin;
3401   ierr = PetscFree(prob->data);CHKERRQ(ierr);
3402   PetscFunctionReturn(0);
3403 }
3404 
3405 static PetscErrorCode PetscDSInitialize_Basic(PetscDS prob)
3406 {
3407   PetscFunctionBegin;
3408   prob->ops->setfromoptions = NULL;
3409   prob->ops->setup          = NULL;
3410   prob->ops->view           = NULL;
3411   prob->ops->destroy        = PetscDSDestroy_Basic;
3412   PetscFunctionReturn(0);
3413 }
3414 
3415 /*MC
3416   PETSCDSBASIC = "basic" - A discrete system with pointwise residual and boundary residual functions
3417 
3418   Level: intermediate
3419 
3420 .seealso: PetscDSType, PetscDSCreate(), PetscDSSetType()
3421 M*/
3422 
3423 PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS prob)
3424 {
3425   PetscDS_Basic *b;
3426   PetscErrorCode      ierr;
3427 
3428   PetscFunctionBegin;
3429   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3430   ierr       = PetscNewLog(prob, &b);CHKERRQ(ierr);
3431   prob->data = b;
3432 
3433   ierr = PetscDSInitialize_Basic(prob);CHKERRQ(ierr);
3434   PetscFunctionReturn(0);
3435 }
3436