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