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