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