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