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