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