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