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