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