xref: /petsc/src/dm/dt/interface/dtds.c (revision 27f02ce888cd6d83c79d307cd15e2865fe9f0ab4)
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*dimEmbed,&prob->f1,
425                       NsMax*NsMax*NqMax*NcMax*NcMax,&prob->g0,NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed,&prob->g1,
426                       NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed,&prob->g2,NsMax*NsMax*NqMax*NcMax*NcMax*dimEmbed*dimEmbed,&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, *tmpgpbd;
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 = PetscCalloc5(NfNew*2, &tmpfbd, NfNew*NfNew*4, &tmpgbd, NfNew*NfNew*4, &tmpgpbd, 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*Nf*4; ++f) tmpgpbd[f] = prob->gpBd[f];
503   for (f = 0; f < Nf; ++f) tmpexactSol[f] = prob->exactSol[f];
504   for (f = 0; f < Nf; ++f) tmpexactCtx[f] = prob->exactCtx[f];
505   for (f = Nf*2; f < NfNew*2; ++f) tmpfbd[f] = NULL;
506   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpgbd[f] = NULL;
507   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpgpbd[f] = NULL;
508   for (f = Nf; f < NfNew; ++f) tmpexactSol[f] = NULL;
509   for (f = Nf; f < NfNew; ++f) tmpexactCtx[f] = NULL;
510   ierr = PetscFree5(prob->fBd, prob->gBd, prob->gpBd, prob->exactSol, prob->exactCtx);CHKERRQ(ierr);
511   prob->fBd = tmpfbd;
512   prob->gBd = tmpgbd;
513   prob->gpBd = tmpgpbd;
514   prob->exactSol = tmpexactSol;
515   prob->exactCtx = tmpexactCtx;
516   PetscFunctionReturn(0);
517 }
518 
519 /*@
520   PetscDSDestroy - Destroys a PetscDS object
521 
522   Collective on prob
523 
524   Input Parameter:
525 . prob - the PetscDS object to destroy
526 
527   Level: developer
528 
529 .seealso PetscDSView()
530 @*/
531 PetscErrorCode PetscDSDestroy(PetscDS *prob)
532 {
533   PetscInt       f;
534   DSBoundary     next;
535   PetscErrorCode ierr;
536 
537   PetscFunctionBegin;
538   if (!*prob) PetscFunctionReturn(0);
539   PetscValidHeaderSpecific((*prob), PETSCDS_CLASSID, 1);
540 
541   if (--((PetscObject)(*prob))->refct > 0) {*prob = 0; PetscFunctionReturn(0);}
542   ((PetscObject) (*prob))->refct = 0;
543   if ((*prob)->subprobs) {
544     PetscInt dim, d;
545 
546     ierr = PetscDSGetSpatialDimension(*prob, &dim);CHKERRQ(ierr);
547     for (d = 0; d < dim; ++d) {ierr = PetscDSDestroy(&(*prob)->subprobs[d]);CHKERRQ(ierr);}
548   }
549   ierr = PetscFree((*prob)->subprobs);CHKERRQ(ierr);
550   ierr = PetscDSDestroyStructs_Static(*prob);CHKERRQ(ierr);
551   for (f = 0; f < (*prob)->Nf; ++f) {
552     ierr = PetscObjectDereference((*prob)->disc[f]);CHKERRQ(ierr);
553   }
554   ierr = PetscFree2((*prob)->disc, (*prob)->implicit);CHKERRQ(ierr);
555   ierr = PetscFree7((*prob)->obj,(*prob)->f,(*prob)->g,(*prob)->gp,(*prob)->gt,(*prob)->r,(*prob)->ctx);CHKERRQ(ierr);
556   ierr = PetscFree((*prob)->update);CHKERRQ(ierr);
557   ierr = PetscFree5((*prob)->fBd,(*prob)->gBd,(*prob)->gpBd,(*prob)->exactSol,(*prob)->exactCtx);CHKERRQ(ierr);
558   if ((*prob)->ops->destroy) {ierr = (*(*prob)->ops->destroy)(*prob);CHKERRQ(ierr);}
559   next = (*prob)->boundary;
560   while (next) {
561     DSBoundary b = next;
562 
563     next = b->next;
564     ierr = PetscFree(b->comps);CHKERRQ(ierr);
565     ierr = PetscFree(b->ids);CHKERRQ(ierr);
566     ierr = PetscFree(b->name);CHKERRQ(ierr);
567     ierr = PetscFree(b->labelname);CHKERRQ(ierr);
568     ierr = PetscFree(b);CHKERRQ(ierr);
569   }
570   ierr = PetscFree((*prob)->constants);CHKERRQ(ierr);
571   ierr = PetscHeaderDestroy(prob);CHKERRQ(ierr);
572   PetscFunctionReturn(0);
573 }
574 
575 /*@
576   PetscDSCreate - Creates an empty PetscDS object. The type can then be set with PetscDSSetType().
577 
578   Collective
579 
580   Input Parameter:
581 . comm - The communicator for the PetscDS object
582 
583   Output Parameter:
584 . prob - The PetscDS object
585 
586   Level: beginner
587 
588 .seealso: PetscDSSetType(), PETSCDSBASIC
589 @*/
590 PetscErrorCode PetscDSCreate(MPI_Comm comm, PetscDS *prob)
591 {
592   PetscDS   p;
593   PetscErrorCode ierr;
594 
595   PetscFunctionBegin;
596   PetscValidPointer(prob, 2);
597   *prob  = NULL;
598   ierr = PetscDSInitializePackage();CHKERRQ(ierr);
599 
600   ierr = PetscHeaderCreate(p, PETSCDS_CLASSID, "PetscDS", "Discrete System", "PetscDS", comm, PetscDSDestroy, PetscDSView);CHKERRQ(ierr);
601 
602   p->Nf           = 0;
603   p->setup        = PETSC_FALSE;
604   p->numConstants = 0;
605   p->constants    = NULL;
606   p->dimEmbed     = -1;
607   p->useJacPre    = PETSC_TRUE;
608 
609   *prob = p;
610   PetscFunctionReturn(0);
611 }
612 
613 /*@
614   PetscDSGetNumFields - Returns the number of fields in the DS
615 
616   Not collective
617 
618   Input Parameter:
619 . prob - The PetscDS object
620 
621   Output Parameter:
622 . Nf - The number of fields
623 
624   Level: beginner
625 
626 .seealso: PetscDSGetSpatialDimension(), PetscDSCreate()
627 @*/
628 PetscErrorCode PetscDSGetNumFields(PetscDS prob, PetscInt *Nf)
629 {
630   PetscFunctionBegin;
631   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
632   PetscValidPointer(Nf, 2);
633   *Nf = prob->Nf;
634   PetscFunctionReturn(0);
635 }
636 
637 /*@
638   PetscDSGetSpatialDimension - Returns the spatial dimension of the DS, meaning the topological dimension of the discretizations
639 
640   Not collective
641 
642   Input Parameter:
643 . prob - The PetscDS object
644 
645   Output Parameter:
646 . dim - The spatial dimension
647 
648   Level: beginner
649 
650 .seealso: PetscDSGetCoordinateDimension(), PetscDSGetNumFields(), PetscDSCreate()
651 @*/
652 PetscErrorCode PetscDSGetSpatialDimension(PetscDS prob, PetscInt *dim)
653 {
654   PetscErrorCode ierr;
655 
656   PetscFunctionBegin;
657   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
658   PetscValidPointer(dim, 2);
659   *dim = 0;
660   if (prob->Nf) {
661     PetscObject  obj;
662     PetscClassId id;
663 
664     ierr = PetscDSGetDiscretization(prob, 0, &obj);CHKERRQ(ierr);
665     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
666     if (id == PETSCFE_CLASSID)      {ierr = PetscFEGetSpatialDimension((PetscFE) obj, dim);CHKERRQ(ierr);}
667     else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetSpatialDimension((PetscFV) obj, dim);CHKERRQ(ierr);}
668     else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", 0);
669   }
670   PetscFunctionReturn(0);
671 }
672 
673 /*@
674   PetscDSGetCoordinateDimension - Returns the coordinate dimension of the DS, meaning the dimension of the space into which the discretiaztions are embedded
675 
676   Not collective
677 
678   Input Parameter:
679 . prob - The PetscDS object
680 
681   Output Parameter:
682 . dimEmbed - The coordinate dimension
683 
684   Level: beginner
685 
686 .seealso: PetscDSSetCoordinateDimension(), PetscDSGetSpatialDimension(), PetscDSGetNumFields(), PetscDSCreate()
687 @*/
688 PetscErrorCode PetscDSGetCoordinateDimension(PetscDS prob, PetscInt *dimEmbed)
689 {
690   PetscFunctionBegin;
691   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
692   PetscValidPointer(dimEmbed, 2);
693   if (prob->dimEmbed < 0) SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONGSTATE, "No coordinate dimension set for this DS");
694   *dimEmbed = prob->dimEmbed;
695   PetscFunctionReturn(0);
696 }
697 
698 /*@
699   PetscDSSetCoordinateDimension - Set the coordinate dimension of the DS, meaning the dimension of the space into which the discretiaztions are embedded
700 
701   Logically collective on prob
702 
703   Input Parameters:
704 + prob - The PetscDS object
705 - dimEmbed - The coordinate dimension
706 
707   Level: beginner
708 
709 .seealso: PetscDSGetCoordinateDimension(), PetscDSGetSpatialDimension(), PetscDSGetNumFields(), PetscDSCreate()
710 @*/
711 PetscErrorCode PetscDSSetCoordinateDimension(PetscDS prob, PetscInt dimEmbed)
712 {
713   PetscFunctionBegin;
714   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
715   if (dimEmbed < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Coordinate dimension must be non-negative, not %D", dimEmbed);
716   prob->dimEmbed = dimEmbed;
717   PetscFunctionReturn(0);
718 }
719 
720 /*@
721   PetscDSGetHybrid - Returns the flag for a hybrid (cohesive) cell
722 
723   Not collective
724 
725   Input Parameter:
726 . prob - The PetscDS object
727 
728   Output Parameter:
729 . isHybrid - The flag
730 
731   Level: developer
732 
733 .seealso: PetscDSSetHybrid(), PetscDSCreate()
734 @*/
735 PetscErrorCode PetscDSGetHybrid(PetscDS prob, PetscBool *isHybrid)
736 {
737   PetscFunctionBegin;
738   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
739   PetscValidPointer(isHybrid, 2);
740   *isHybrid = prob->isHybrid;
741   PetscFunctionReturn(0);
742 }
743 
744 /*@
745   PetscDSSetHybrid - Set the flag for a hybrid (cohesive) cell
746 
747   Not collective
748 
749   Input Parameters:
750 + prob - The PetscDS object
751 - isHybrid - The flag
752 
753   Level: developer
754 
755 .seealso: PetscDSGetHybrid(), PetscDSCreate()
756 @*/
757 PetscErrorCode PetscDSSetHybrid(PetscDS prob, PetscBool isHybrid)
758 {
759   PetscFunctionBegin;
760   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
761   prob->isHybrid = isHybrid;
762   PetscFunctionReturn(0);
763 }
764 
765 /*@
766   PetscDSGetTotalDimension - Returns the total size of the approximation space for this system
767 
768   Not collective
769 
770   Input Parameter:
771 . prob - The PetscDS object
772 
773   Output Parameter:
774 . dim - The total problem dimension
775 
776   Level: beginner
777 
778 .seealso: PetscDSGetNumFields(), PetscDSCreate()
779 @*/
780 PetscErrorCode PetscDSGetTotalDimension(PetscDS prob, PetscInt *dim)
781 {
782   PetscErrorCode ierr;
783 
784   PetscFunctionBegin;
785   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
786   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
787   PetscValidPointer(dim, 2);
788   *dim = prob->totDim;
789   PetscFunctionReturn(0);
790 }
791 
792 /*@
793   PetscDSGetTotalComponents - Returns the total number of components in this system
794 
795   Not collective
796 
797   Input Parameter:
798 . prob - The PetscDS object
799 
800   Output Parameter:
801 . dim - The total number of components
802 
803   Level: beginner
804 
805 .seealso: PetscDSGetNumFields(), PetscDSCreate()
806 @*/
807 PetscErrorCode PetscDSGetTotalComponents(PetscDS prob, PetscInt *Nc)
808 {
809   PetscErrorCode ierr;
810 
811   PetscFunctionBegin;
812   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
813   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
814   PetscValidPointer(Nc, 2);
815   *Nc = prob->totComp;
816   PetscFunctionReturn(0);
817 }
818 
819 /*@
820   PetscDSGetDiscretization - Returns the discretization object for the given field
821 
822   Not collective
823 
824   Input Parameters:
825 + prob - The PetscDS object
826 - f - The field number
827 
828   Output Parameter:
829 . disc - The discretization object
830 
831   Level: beginner
832 
833 .seealso: PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
834 @*/
835 PetscErrorCode PetscDSGetDiscretization(PetscDS prob, PetscInt f, PetscObject *disc)
836 {
837   PetscFunctionBegin;
838   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
839   PetscValidPointer(disc, 3);
840   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);
841   *disc = prob->disc[f];
842   PetscFunctionReturn(0);
843 }
844 
845 /*@
846   PetscDSSetDiscretization - Sets the discretization object for the given field
847 
848   Not collective
849 
850   Input Parameters:
851 + prob - The PetscDS object
852 . f - The field number
853 - disc - The discretization object
854 
855   Level: beginner
856 
857 .seealso: PetscDSGetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
858 @*/
859 PetscErrorCode PetscDSSetDiscretization(PetscDS prob, PetscInt f, PetscObject disc)
860 {
861   PetscErrorCode ierr;
862 
863   PetscFunctionBegin;
864   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
865   PetscValidPointer(disc, 3);
866   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
867   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
868   ierr = PetscObjectDereference(prob->disc[f]);CHKERRQ(ierr);
869   prob->disc[f] = disc;
870   ierr = PetscObjectReference(disc);CHKERRQ(ierr);
871   {
872     PetscClassId id;
873 
874     ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
875     if (id == PETSCFE_CLASSID) {
876       ierr = PetscDSSetImplicit(prob, f, PETSC_TRUE);CHKERRQ(ierr);
877     } else if (id == PETSCFV_CLASSID) {
878       ierr = PetscDSSetImplicit(prob, f, PETSC_FALSE);CHKERRQ(ierr);
879     }
880   }
881   PetscFunctionReturn(0);
882 }
883 
884 /*@
885   PetscDSAddDiscretization - Adds a discretization object
886 
887   Not collective
888 
889   Input Parameters:
890 + prob - The PetscDS object
891 - disc - The boundary discretization object
892 
893   Level: beginner
894 
895 .seealso: PetscDSGetDiscretization(), PetscDSSetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
896 @*/
897 PetscErrorCode PetscDSAddDiscretization(PetscDS prob, PetscObject disc)
898 {
899   PetscErrorCode ierr;
900 
901   PetscFunctionBegin;
902   ierr = PetscDSSetDiscretization(prob, prob->Nf, disc);CHKERRQ(ierr);
903   PetscFunctionReturn(0);
904 }
905 
906 /*@
907   PetscDSGetImplicit - Returns the flag for implicit solve for this field. This is just a guide for IMEX
908 
909   Not collective
910 
911   Input Parameters:
912 + prob - The PetscDS object
913 - f - The field number
914 
915   Output Parameter:
916 . implicit - The flag indicating what kind of solve to use for this field
917 
918   Level: developer
919 
920 .seealso: PetscDSSetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
921 @*/
922 PetscErrorCode PetscDSGetImplicit(PetscDS prob, PetscInt f, PetscBool *implicit)
923 {
924   PetscFunctionBegin;
925   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
926   PetscValidPointer(implicit, 3);
927   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);
928   *implicit = prob->implicit[f];
929   PetscFunctionReturn(0);
930 }
931 
932 /*@
933   PetscDSSetImplicit - Set the flag for implicit solve for this field. This is just a guide for IMEX
934 
935   Not collective
936 
937   Input Parameters:
938 + prob - The PetscDS object
939 . f - The field number
940 - implicit - The flag indicating what kind of solve to use for this field
941 
942   Level: developer
943 
944 .seealso: PetscDSGetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
945 @*/
946 PetscErrorCode PetscDSSetImplicit(PetscDS prob, PetscInt f, PetscBool implicit)
947 {
948   PetscFunctionBegin;
949   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
950   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);
951   prob->implicit[f] = implicit;
952   PetscFunctionReturn(0);
953 }
954 
955 PetscErrorCode PetscDSGetObjective(PetscDS prob, PetscInt f,
956                                    void (**obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
957                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
958                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
959                                                 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
960 {
961   PetscFunctionBegin;
962   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
963   PetscValidPointer(obj, 2);
964   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);
965   *obj = prob->obj[f];
966   PetscFunctionReturn(0);
967 }
968 
969 PetscErrorCode PetscDSSetObjective(PetscDS prob, PetscInt f,
970                                    void (*obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
971                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
972                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
973                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar obj[]))
974 {
975   PetscErrorCode ierr;
976 
977   PetscFunctionBegin;
978   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
979   if (obj) PetscValidFunction(obj, 2);
980   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
981   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
982   prob->obj[f] = obj;
983   PetscFunctionReturn(0);
984 }
985 
986 /*@C
987   PetscDSGetResidual - Get the pointwise residual function for a given test field
988 
989   Not collective
990 
991   Input Parameters:
992 + prob - The PetscDS
993 - f    - The test field number
994 
995   Output Parameters:
996 + f0 - integrand for the test function term
997 - f1 - integrand for the test function gradient term
998 
999   Note: We are using a first order FEM model for the weak form:
1000 
1001   \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)
1002 
1003 The calling sequence for the callbacks f0 and f1 is given by:
1004 
1005 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1006 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1007 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1008 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
1009 
1010 + dim - the spatial dimension
1011 . Nf - the number of fields
1012 . uOff - the offset into u[] and u_t[] for each field
1013 . uOff_x - the offset into u_x[] for each field
1014 . u - each field evaluated at the current point
1015 . u_t - the time derivative of each field evaluated at the current point
1016 . u_x - the gradient of each field evaluated at the current point
1017 . aOff - the offset into a[] and a_t[] for each auxiliary field
1018 . aOff_x - the offset into a_x[] for each auxiliary field
1019 . a - each auxiliary field evaluated at the current point
1020 . a_t - the time derivative of each auxiliary field evaluated at the current point
1021 . a_x - the gradient of auxiliary each field evaluated at the current point
1022 . t - current time
1023 . x - coordinates of the current point
1024 . numConstants - number of constant parameters
1025 . constants - constant parameters
1026 - f0 - output values at the current point
1027 
1028   Level: intermediate
1029 
1030 .seealso: PetscDSSetResidual()
1031 @*/
1032 PetscErrorCode PetscDSGetResidual(PetscDS prob, PetscInt f,
1033                                   void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1034                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1035                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1036                                               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1037                                   void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1038                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1039                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1040                                               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1041 {
1042   PetscFunctionBegin;
1043   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1044   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);
1045   if (f0) {PetscValidPointer(f0, 3); *f0 = prob->f[f*2+0];}
1046   if (f1) {PetscValidPointer(f1, 4); *f1 = prob->f[f*2+1];}
1047   PetscFunctionReturn(0);
1048 }
1049 
1050 /*@C
1051   PetscDSSetResidual - Set the pointwise residual function for a given test field
1052 
1053   Not collective
1054 
1055   Input Parameters:
1056 + prob - The PetscDS
1057 . f    - The test field number
1058 . f0 - integrand for the test function term
1059 - f1 - integrand for the test function gradient term
1060 
1061   Note: We are using a first order FEM model for the weak form:
1062 
1063   \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)
1064 
1065 The calling sequence for the callbacks f0 and f1 is given by:
1066 
1067 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1068 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1069 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1070 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
1071 
1072 + dim - the spatial dimension
1073 . Nf - the number of fields
1074 . uOff - the offset into u[] and u_t[] for each field
1075 . uOff_x - the offset into u_x[] for each field
1076 . u - each field evaluated at the current point
1077 . u_t - the time derivative of each field evaluated at the current point
1078 . u_x - the gradient of each field evaluated at the current point
1079 . aOff - the offset into a[] and a_t[] for each auxiliary field
1080 . aOff_x - the offset into a_x[] for each auxiliary field
1081 . a - each auxiliary field evaluated at the current point
1082 . a_t - the time derivative of each auxiliary field evaluated at the current point
1083 . a_x - the gradient of auxiliary each field evaluated at the current point
1084 . t - current time
1085 . x - coordinates of the current point
1086 . numConstants - number of constant parameters
1087 . constants - constant parameters
1088 - f0 - output values at the current point
1089 
1090   Level: intermediate
1091 
1092 .seealso: PetscDSGetResidual()
1093 @*/
1094 PetscErrorCode PetscDSSetResidual(PetscDS prob, PetscInt f,
1095                                   void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1096                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1097                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1098                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1099                                   void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1100                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1101                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1102                                              PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1103 {
1104   PetscErrorCode ierr;
1105 
1106   PetscFunctionBegin;
1107   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1108   if (f0) PetscValidFunction(f0, 3);
1109   if (f1) PetscValidFunction(f1, 4);
1110   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1111   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1112   prob->f[f*2+0] = f0;
1113   prob->f[f*2+1] = f1;
1114   PetscFunctionReturn(0);
1115 }
1116 
1117 /*@C
1118   PetscDSHasJacobian - Signals that Jacobian functions have been set
1119 
1120   Not collective
1121 
1122   Input Parameter:
1123 . prob - The PetscDS
1124 
1125   Output Parameter:
1126 . hasJac - flag that pointwise function for the Jacobian has been set
1127 
1128   Level: intermediate
1129 
1130 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1131 @*/
1132 PetscErrorCode PetscDSHasJacobian(PetscDS prob, PetscBool *hasJac)
1133 {
1134   PetscInt f, g, h;
1135 
1136   PetscFunctionBegin;
1137   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1138   *hasJac = PETSC_FALSE;
1139   for (f = 0; f < prob->Nf; ++f) {
1140     for (g = 0; g < prob->Nf; ++g) {
1141       for (h = 0; h < 4; ++h) {
1142         if (prob->g[(f*prob->Nf + g)*4+h]) *hasJac = PETSC_TRUE;
1143       }
1144     }
1145   }
1146   PetscFunctionReturn(0);
1147 }
1148 
1149 /*@C
1150   PetscDSGetJacobian - Get the pointwise Jacobian function for given test and basis field
1151 
1152   Not collective
1153 
1154   Input Parameters:
1155 + prob - The PetscDS
1156 . f    - The test field number
1157 - g    - The field number
1158 
1159   Output Parameters:
1160 + g0 - integrand for the test and basis function term
1161 . g1 - integrand for the test function and basis function gradient term
1162 . g2 - integrand for the test function gradient and basis function term
1163 - g3 - integrand for the test function gradient and basis function gradient term
1164 
1165   Note: We are using a first order FEM model for the weak form:
1166 
1167   \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
1168 
1169 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1170 
1171 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1172 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1173 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1174 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1175 
1176 + dim - the spatial dimension
1177 . Nf - the number of fields
1178 . uOff - the offset into u[] and u_t[] for each field
1179 . uOff_x - the offset into u_x[] for each field
1180 . u - each field evaluated at the current point
1181 . u_t - the time derivative of each field evaluated at the current point
1182 . u_x - the gradient of each field evaluated at the current point
1183 . aOff - the offset into a[] and a_t[] for each auxiliary field
1184 . aOff_x - the offset into a_x[] for each auxiliary field
1185 . a - each auxiliary field evaluated at the current point
1186 . a_t - the time derivative of each auxiliary field evaluated at the current point
1187 . a_x - the gradient of auxiliary each field evaluated at the current point
1188 . t - current time
1189 . u_tShift - the multiplier a for dF/dU_t
1190 . x - coordinates of the current point
1191 . numConstants - number of constant parameters
1192 . constants - constant parameters
1193 - g0 - output values at the current point
1194 
1195   Level: intermediate
1196 
1197 .seealso: PetscDSSetJacobian()
1198 @*/
1199 PetscErrorCode PetscDSGetJacobian(PetscDS prob, PetscInt f, PetscInt g,
1200                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1201                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1202                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1203                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1204                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1205                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1206                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1207                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1208                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1209                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1210                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1211                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1212                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1213                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1214                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1215                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1216 {
1217   PetscFunctionBegin;
1218   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1219   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);
1220   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);
1221   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->g[(f*prob->Nf + g)*4+0];}
1222   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->g[(f*prob->Nf + g)*4+1];}
1223   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->g[(f*prob->Nf + g)*4+2];}
1224   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->g[(f*prob->Nf + g)*4+3];}
1225   PetscFunctionReturn(0);
1226 }
1227 
1228 /*@C
1229   PetscDSSetJacobian - Set the pointwise Jacobian function for given test and basis fields
1230 
1231   Not collective
1232 
1233   Input Parameters:
1234 + prob - The PetscDS
1235 . f    - The test field number
1236 . g    - The field number
1237 . g0 - integrand for the test and basis function term
1238 . g1 - integrand for the test function and basis function gradient term
1239 . g2 - integrand for the test function gradient and basis function term
1240 - g3 - integrand for the test function gradient and basis function gradient term
1241 
1242   Note: We are using a first order FEM model for the weak form:
1243 
1244   \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
1245 
1246 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1247 
1248 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1249 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1250 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1251 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1252 
1253 + dim - the spatial dimension
1254 . Nf - the number of fields
1255 . uOff - the offset into u[] and u_t[] for each field
1256 . uOff_x - the offset into u_x[] for each field
1257 . u - each field evaluated at the current point
1258 . u_t - the time derivative of each field evaluated at the current point
1259 . u_x - the gradient of each field evaluated at the current point
1260 . aOff - the offset into a[] and a_t[] for each auxiliary field
1261 . aOff_x - the offset into a_x[] for each auxiliary field
1262 . a - each auxiliary field evaluated at the current point
1263 . a_t - the time derivative of each auxiliary field evaluated at the current point
1264 . a_x - the gradient of auxiliary each field evaluated at the current point
1265 . t - current time
1266 . u_tShift - the multiplier a for dF/dU_t
1267 . x - coordinates of the current point
1268 . numConstants - number of constant parameters
1269 . constants - constant parameters
1270 - g0 - output values at the current point
1271 
1272   Level: intermediate
1273 
1274 .seealso: PetscDSGetJacobian()
1275 @*/
1276 PetscErrorCode PetscDSSetJacobian(PetscDS prob, PetscInt f, PetscInt g,
1277                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1278                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1279                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1280                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1281                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1282                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1283                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1284                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1285                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1286                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1287                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1288                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1289                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1290                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1291                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1292                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1293 {
1294   PetscErrorCode ierr;
1295 
1296   PetscFunctionBegin;
1297   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1298   if (g0) PetscValidFunction(g0, 4);
1299   if (g1) PetscValidFunction(g1, 5);
1300   if (g2) PetscValidFunction(g2, 6);
1301   if (g3) PetscValidFunction(g3, 7);
1302   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1303   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1304   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1305   prob->g[(f*prob->Nf + g)*4+0] = g0;
1306   prob->g[(f*prob->Nf + g)*4+1] = g1;
1307   prob->g[(f*prob->Nf + g)*4+2] = g2;
1308   prob->g[(f*prob->Nf + g)*4+3] = g3;
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 /*@C
1313   PetscDSUseJacobianPreconditioner - Whether to construct a Jacobian preconditioner
1314 
1315   Not collective
1316 
1317   Input Parameters:
1318 + prob - The PetscDS
1319 - useJacPre - flag that enables construction of a Jacobian preconditioner
1320 
1321   Level: intermediate
1322 
1323 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1324 @*/
1325 PetscErrorCode PetscDSUseJacobianPreconditioner(PetscDS prob, PetscBool useJacPre)
1326 {
1327   PetscFunctionBegin;
1328   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1329   prob->useJacPre = useJacPre;
1330   PetscFunctionReturn(0);
1331 }
1332 
1333 /*@C
1334   PetscDSHasJacobianPreconditioner - Signals that a Jacobian preconditioner matrix has been set
1335 
1336   Not collective
1337 
1338   Input Parameter:
1339 . prob - The PetscDS
1340 
1341   Output Parameter:
1342 . hasJacPre - flag that pointwise function for Jacobian preconditioner matrix has been set
1343 
1344   Level: intermediate
1345 
1346 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1347 @*/
1348 PetscErrorCode PetscDSHasJacobianPreconditioner(PetscDS prob, PetscBool *hasJacPre)
1349 {
1350   PetscInt f, g, h;
1351 
1352   PetscFunctionBegin;
1353   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1354   *hasJacPre = PETSC_FALSE;
1355   if (!prob->useJacPre) PetscFunctionReturn(0);
1356   for (f = 0; f < prob->Nf; ++f) {
1357     for (g = 0; g < prob->Nf; ++g) {
1358       for (h = 0; h < 4; ++h) {
1359         if (prob->gp[(f*prob->Nf + g)*4+h]) *hasJacPre = PETSC_TRUE;
1360       }
1361     }
1362   }
1363   PetscFunctionReturn(0);
1364 }
1365 
1366 /*@C
1367   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.
1368 
1369   Not collective
1370 
1371   Input Parameters:
1372 + prob - The PetscDS
1373 . f    - The test field number
1374 - g    - The field number
1375 
1376   Output Parameters:
1377 + g0 - integrand for the test and basis function term
1378 . g1 - integrand for the test function and basis function gradient term
1379 . g2 - integrand for the test function gradient and basis function term
1380 - g3 - integrand for the test function gradient and basis function gradient term
1381 
1382   Note: We are using a first order FEM model for the weak form:
1383 
1384   \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
1385 
1386 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1387 
1388 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1389 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1390 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1391 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1392 
1393 + dim - the spatial dimension
1394 . Nf - the number of fields
1395 . uOff - the offset into u[] and u_t[] for each field
1396 . uOff_x - the offset into u_x[] for each field
1397 . u - each field evaluated at the current point
1398 . u_t - the time derivative of each field evaluated at the current point
1399 . u_x - the gradient of each field evaluated at the current point
1400 . aOff - the offset into a[] and a_t[] for each auxiliary field
1401 . aOff_x - the offset into a_x[] for each auxiliary field
1402 . a - each auxiliary field evaluated at the current point
1403 . a_t - the time derivative of each auxiliary field evaluated at the current point
1404 . a_x - the gradient of auxiliary each field evaluated at the current point
1405 . t - current time
1406 . u_tShift - the multiplier a for dF/dU_t
1407 . x - coordinates of the current point
1408 . numConstants - number of constant parameters
1409 . constants - constant parameters
1410 - g0 - output values at the current point
1411 
1412   Level: intermediate
1413 
1414 .seealso: PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1415 @*/
1416 PetscErrorCode PetscDSGetJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
1417                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1418                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1419                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1420                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1421                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1422                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1423                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1424                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1425                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1426                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1427                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1428                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1429                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1430                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1431                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1432                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1433 {
1434   PetscFunctionBegin;
1435   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1436   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);
1437   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);
1438   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gp[(f*prob->Nf + g)*4+0];}
1439   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gp[(f*prob->Nf + g)*4+1];}
1440   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gp[(f*prob->Nf + g)*4+2];}
1441   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gp[(f*prob->Nf + g)*4+3];}
1442   PetscFunctionReturn(0);
1443 }
1444 
1445 /*@C
1446   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.
1447 
1448   Not collective
1449 
1450   Input Parameters:
1451 + prob - The PetscDS
1452 . f    - The test field number
1453 . g    - The field number
1454 . g0 - integrand for the test and basis function term
1455 . g1 - integrand for the test function and basis function gradient term
1456 . g2 - integrand for the test function gradient and basis function term
1457 - g3 - integrand for the test function gradient and basis function gradient term
1458 
1459   Note: We are using a first order FEM model for the weak form:
1460 
1461   \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
1462 
1463 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1464 
1465 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1466 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1467 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1468 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1469 
1470 + dim - the spatial dimension
1471 . Nf - the number of fields
1472 . uOff - the offset into u[] and u_t[] for each field
1473 . uOff_x - the offset into u_x[] for each field
1474 . u - each field evaluated at the current point
1475 . u_t - the time derivative of each field evaluated at the current point
1476 . u_x - the gradient of each field evaluated at the current point
1477 . aOff - the offset into a[] and a_t[] for each auxiliary field
1478 . aOff_x - the offset into a_x[] for each auxiliary field
1479 . a - each auxiliary field evaluated at the current point
1480 . a_t - the time derivative of each auxiliary field evaluated at the current point
1481 . a_x - the gradient of auxiliary each field evaluated at the current point
1482 . t - current time
1483 . u_tShift - the multiplier a for dF/dU_t
1484 . x - coordinates of the current point
1485 . numConstants - number of constant parameters
1486 . constants - constant parameters
1487 - g0 - output values at the current point
1488 
1489   Level: intermediate
1490 
1491 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobian()
1492 @*/
1493 PetscErrorCode PetscDSSetJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
1494                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1495                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1496                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1497                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1498                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1499                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1500                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1501                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1502                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1503                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1504                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1505                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1506                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1507                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1508                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1509                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1510 {
1511   PetscErrorCode ierr;
1512 
1513   PetscFunctionBegin;
1514   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1515   if (g0) PetscValidFunction(g0, 4);
1516   if (g1) PetscValidFunction(g1, 5);
1517   if (g2) PetscValidFunction(g2, 6);
1518   if (g3) PetscValidFunction(g3, 7);
1519   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1520   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1521   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1522   prob->gp[(f*prob->Nf + g)*4+0] = g0;
1523   prob->gp[(f*prob->Nf + g)*4+1] = g1;
1524   prob->gp[(f*prob->Nf + g)*4+2] = g2;
1525   prob->gp[(f*prob->Nf + g)*4+3] = g3;
1526   PetscFunctionReturn(0);
1527 }
1528 
1529 /*@C
1530   PetscDSHasDynamicJacobian - Signals that a dynamic Jacobian, dF/du_t, has been set
1531 
1532   Not collective
1533 
1534   Input Parameter:
1535 . prob - The PetscDS
1536 
1537   Output Parameter:
1538 . hasDynJac - flag that pointwise function for dynamic Jacobian has been set
1539 
1540   Level: intermediate
1541 
1542 .seealso: PetscDSGetDynamicJacobian(), PetscDSSetDynamicJacobian(), PetscDSGetJacobian()
1543 @*/
1544 PetscErrorCode PetscDSHasDynamicJacobian(PetscDS prob, PetscBool *hasDynJac)
1545 {
1546   PetscInt f, g, h;
1547 
1548   PetscFunctionBegin;
1549   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1550   *hasDynJac = PETSC_FALSE;
1551   for (f = 0; f < prob->Nf; ++f) {
1552     for (g = 0; g < prob->Nf; ++g) {
1553       for (h = 0; h < 4; ++h) {
1554         if (prob->gt[(f*prob->Nf + g)*4+h]) *hasDynJac = PETSC_TRUE;
1555       }
1556     }
1557   }
1558   PetscFunctionReturn(0);
1559 }
1560 
1561 /*@C
1562   PetscDSGetDynamicJacobian - Get the pointwise dynamic Jacobian, dF/du_t, function for given test and basis field
1563 
1564   Not collective
1565 
1566   Input Parameters:
1567 + prob - The PetscDS
1568 . f    - The test field number
1569 - g    - The field number
1570 
1571   Output Parameters:
1572 + g0 - integrand for the test and basis function term
1573 . g1 - integrand for the test function and basis function gradient term
1574 . g2 - integrand for the test function gradient and basis function term
1575 - g3 - integrand for the test function gradient and basis function gradient term
1576 
1577   Note: We are using a first order FEM model for the weak form:
1578 
1579   \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
1580 
1581 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1582 
1583 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1584 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1585 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1586 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1587 
1588 + dim - the spatial dimension
1589 . Nf - the number of fields
1590 . uOff - the offset into u[] and u_t[] for each field
1591 . uOff_x - the offset into u_x[] for each field
1592 . u - each field evaluated at the current point
1593 . u_t - the time derivative of each field evaluated at the current point
1594 . u_x - the gradient of each field evaluated at the current point
1595 . aOff - the offset into a[] and a_t[] for each auxiliary field
1596 . aOff_x - the offset into a_x[] for each auxiliary field
1597 . a - each auxiliary field evaluated at the current point
1598 . a_t - the time derivative of each auxiliary field evaluated at the current point
1599 . a_x - the gradient of auxiliary each field evaluated at the current point
1600 . t - current time
1601 . u_tShift - the multiplier a for dF/dU_t
1602 . x - coordinates of the current point
1603 . numConstants - number of constant parameters
1604 . constants - constant parameters
1605 - g0 - output values at the current point
1606 
1607   Level: intermediate
1608 
1609 .seealso: PetscDSSetJacobian()
1610 @*/
1611 PetscErrorCode PetscDSGetDynamicJacobian(PetscDS prob, PetscInt f, PetscInt g,
1612                                          void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1613                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1614                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1615                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1616                                          void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1617                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1618                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1619                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1620                                          void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1621                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1622                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1623                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1624                                          void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1625                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1626                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1627                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1628 {
1629   PetscFunctionBegin;
1630   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1631   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);
1632   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);
1633   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gt[(f*prob->Nf + g)*4+0];}
1634   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gt[(f*prob->Nf + g)*4+1];}
1635   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gt[(f*prob->Nf + g)*4+2];}
1636   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gt[(f*prob->Nf + g)*4+3];}
1637   PetscFunctionReturn(0);
1638 }
1639 
1640 /*@C
1641   PetscDSSetDynamicJacobian - Set the pointwise dynamic Jacobian, dF/du_t, function for given test and basis fields
1642 
1643   Not collective
1644 
1645   Input Parameters:
1646 + prob - The PetscDS
1647 . f    - The test field number
1648 . g    - The field number
1649 . g0 - integrand for the test and basis function term
1650 . g1 - integrand for the test function and basis function gradient term
1651 . g2 - integrand for the test function gradient and basis function term
1652 - g3 - integrand for the test function gradient and basis function gradient term
1653 
1654   Note: We are using a first order FEM model for the weak form:
1655 
1656   \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
1657 
1658 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1659 
1660 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1661 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1662 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1663 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1664 
1665 + dim - the spatial dimension
1666 . Nf - the number of fields
1667 . uOff - the offset into u[] and u_t[] for each field
1668 . uOff_x - the offset into u_x[] for each field
1669 . u - each field evaluated at the current point
1670 . u_t - the time derivative of each field evaluated at the current point
1671 . u_x - the gradient of each field evaluated at the current point
1672 . aOff - the offset into a[] and a_t[] for each auxiliary field
1673 . aOff_x - the offset into a_x[] for each auxiliary field
1674 . a - each auxiliary field evaluated at the current point
1675 . a_t - the time derivative of each auxiliary field evaluated at the current point
1676 . a_x - the gradient of auxiliary each field evaluated at the current point
1677 . t - current time
1678 . u_tShift - the multiplier a for dF/dU_t
1679 . x - coordinates of the current point
1680 . numConstants - number of constant parameters
1681 . constants - constant parameters
1682 - g0 - output values at the current point
1683 
1684   Level: intermediate
1685 
1686 .seealso: PetscDSGetJacobian()
1687 @*/
1688 PetscErrorCode PetscDSSetDynamicJacobian(PetscDS prob, PetscInt f, PetscInt g,
1689                                          void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1690                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1691                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1692                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
1693                                          void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1694                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1695                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1696                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
1697                                          void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1698                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1699                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1700                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
1701                                          void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1702                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1703                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1704                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
1705 {
1706   PetscErrorCode ierr;
1707 
1708   PetscFunctionBegin;
1709   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1710   if (g0) PetscValidFunction(g0, 4);
1711   if (g1) PetscValidFunction(g1, 5);
1712   if (g2) PetscValidFunction(g2, 6);
1713   if (g3) PetscValidFunction(g3, 7);
1714   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1715   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1716   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1717   prob->gt[(f*prob->Nf + g)*4+0] = g0;
1718   prob->gt[(f*prob->Nf + g)*4+1] = g1;
1719   prob->gt[(f*prob->Nf + g)*4+2] = g2;
1720   prob->gt[(f*prob->Nf + g)*4+3] = g3;
1721   PetscFunctionReturn(0);
1722 }
1723 
1724 /*@C
1725   PetscDSGetRiemannSolver - Returns the Riemann solver for the given field
1726 
1727   Not collective
1728 
1729   Input Arguments:
1730 + prob - The PetscDS object
1731 - f    - The field number
1732 
1733   Output Argument:
1734 . r    - Riemann solver
1735 
1736   Calling sequence for r:
1737 
1738 $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)
1739 
1740 + dim  - The spatial dimension
1741 . Nf   - The number of fields
1742 . x    - The coordinates at a point on the interface
1743 . n    - The normal vector to the interface
1744 . uL   - The state vector to the left of the interface
1745 . uR   - The state vector to the right of the interface
1746 . flux - output array of flux through the interface
1747 . numConstants - number of constant parameters
1748 . constants - constant parameters
1749 - ctx  - optional user context
1750 
1751   Level: intermediate
1752 
1753 .seealso: PetscDSSetRiemannSolver()
1754 @*/
1755 PetscErrorCode PetscDSGetRiemannSolver(PetscDS prob, PetscInt f,
1756                                        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))
1757 {
1758   PetscFunctionBegin;
1759   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1760   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);
1761   PetscValidPointer(r, 3);
1762   *r = prob->r[f];
1763   PetscFunctionReturn(0);
1764 }
1765 
1766 /*@C
1767   PetscDSSetRiemannSolver - Sets the Riemann solver for the given field
1768 
1769   Not collective
1770 
1771   Input Arguments:
1772 + prob - The PetscDS object
1773 . f    - The field number
1774 - r    - Riemann solver
1775 
1776   Calling sequence for r:
1777 
1778 $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)
1779 
1780 + dim  - The spatial dimension
1781 . Nf   - The number of fields
1782 . x    - The coordinates at a point on the interface
1783 . n    - The normal vector to the interface
1784 . uL   - The state vector to the left of the interface
1785 . uR   - The state vector to the right of the interface
1786 . flux - output array of flux through the interface
1787 . numConstants - number of constant parameters
1788 . constants - constant parameters
1789 - ctx  - optional user context
1790 
1791   Level: intermediate
1792 
1793 .seealso: PetscDSGetRiemannSolver()
1794 @*/
1795 PetscErrorCode PetscDSSetRiemannSolver(PetscDS prob, PetscInt f,
1796                                        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))
1797 {
1798   PetscErrorCode ierr;
1799 
1800   PetscFunctionBegin;
1801   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1802   if (r) PetscValidFunction(r, 3);
1803   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1804   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1805   prob->r[f] = r;
1806   PetscFunctionReturn(0);
1807 }
1808 
1809 /*@C
1810   PetscDSGetUpdate - Get the pointwise update function for a given field
1811 
1812   Not collective
1813 
1814   Input Parameters:
1815 + prob - The PetscDS
1816 - f    - The field number
1817 
1818   Output Parameters:
1819 . update - update function
1820 
1821   Note: The calling sequence for the callback update is given by:
1822 
1823 $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1824 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1825 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1826 $        PetscReal t, const PetscReal x[], PetscScalar uNew[])
1827 
1828 + dim - the spatial dimension
1829 . Nf - the number of fields
1830 . uOff - the offset into u[] and u_t[] for each field
1831 . uOff_x - the offset into u_x[] for each field
1832 . u - each field evaluated at the current point
1833 . u_t - the time derivative of each field evaluated at the current point
1834 . u_x - the gradient of each field evaluated at the current point
1835 . aOff - the offset into a[] and a_t[] for each auxiliary field
1836 . aOff_x - the offset into a_x[] for each auxiliary field
1837 . a - each auxiliary field evaluated at the current point
1838 . a_t - the time derivative of each auxiliary field evaluated at the current point
1839 . a_x - the gradient of auxiliary each field evaluated at the current point
1840 . t - current time
1841 . x - coordinates of the current point
1842 - uNew - new value for field at the current point
1843 
1844   Level: intermediate
1845 
1846 .seealso: PetscDSSetUpdate(), PetscDSSetResidual()
1847 @*/
1848 PetscErrorCode PetscDSGetUpdate(PetscDS prob, PetscInt f,
1849                                   void (**update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1850                                                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1851                                                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1852                                                   PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
1853 {
1854   PetscFunctionBegin;
1855   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1856   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);
1857   if (update) {PetscValidPointer(update, 3); *update = prob->update[f];}
1858   PetscFunctionReturn(0);
1859 }
1860 
1861 /*@C
1862   PetscDSSetUpdate - Set the pointwise update function for a given field
1863 
1864   Not collective
1865 
1866   Input Parameters:
1867 + prob   - The PetscDS
1868 . f      - The field number
1869 - update - update function
1870 
1871   Note: The calling sequence for the callback update is given by:
1872 
1873 $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1874 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1875 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1876 $        PetscReal t, const PetscReal x[], PetscScalar uNew[])
1877 
1878 + dim - the spatial dimension
1879 . Nf - the number of fields
1880 . uOff - the offset into u[] and u_t[] for each field
1881 . uOff_x - the offset into u_x[] for each field
1882 . u - each field evaluated at the current point
1883 . u_t - the time derivative of each field evaluated at the current point
1884 . u_x - the gradient of each field evaluated at the current point
1885 . aOff - the offset into a[] and a_t[] for each auxiliary field
1886 . aOff_x - the offset into a_x[] for each auxiliary field
1887 . a - each auxiliary field evaluated at the current point
1888 . a_t - the time derivative of each auxiliary field evaluated at the current point
1889 . a_x - the gradient of auxiliary each field evaluated at the current point
1890 . t - current time
1891 . x - coordinates of the current point
1892 - uNew - new field values at the current point
1893 
1894   Level: intermediate
1895 
1896 .seealso: PetscDSGetResidual()
1897 @*/
1898 PetscErrorCode PetscDSSetUpdate(PetscDS prob, PetscInt f,
1899                                 void (*update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1900                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1901                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1902                                                PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar uNew[]))
1903 {
1904   PetscErrorCode ierr;
1905 
1906   PetscFunctionBegin;
1907   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1908   if (update) PetscValidFunction(update, 3);
1909   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1910   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1911   prob->update[f] = update;
1912   PetscFunctionReturn(0);
1913 }
1914 
1915 PetscErrorCode PetscDSGetContext(PetscDS prob, PetscInt f, void **ctx)
1916 {
1917   PetscFunctionBegin;
1918   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1919   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);
1920   PetscValidPointer(ctx, 3);
1921   *ctx = prob->ctx[f];
1922   PetscFunctionReturn(0);
1923 }
1924 
1925 PetscErrorCode PetscDSSetContext(PetscDS prob, PetscInt f, void *ctx)
1926 {
1927   PetscErrorCode ierr;
1928 
1929   PetscFunctionBegin;
1930   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1931   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1932   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1933   prob->ctx[f] = ctx;
1934   PetscFunctionReturn(0);
1935 }
1936 
1937 /*@C
1938   PetscDSGetBdResidual - Get the pointwise boundary residual function for a given test field
1939 
1940   Not collective
1941 
1942   Input Parameters:
1943 + prob - The PetscDS
1944 - f    - The test field number
1945 
1946   Output Parameters:
1947 + f0 - boundary integrand for the test function term
1948 - f1 - boundary integrand for the test function gradient term
1949 
1950   Note: We are using a first order FEM model for the weak form:
1951 
1952   \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
1953 
1954 The calling sequence for the callbacks f0 and f1 is given by:
1955 
1956 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1957 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1958 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1959 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
1960 
1961 + dim - the spatial dimension
1962 . Nf - the number of fields
1963 . uOff - the offset into u[] and u_t[] for each field
1964 . uOff_x - the offset into u_x[] for each field
1965 . u - each field evaluated at the current point
1966 . u_t - the time derivative of each field evaluated at the current point
1967 . u_x - the gradient of each field evaluated at the current point
1968 . aOff - the offset into a[] and a_t[] for each auxiliary field
1969 . aOff_x - the offset into a_x[] for each auxiliary field
1970 . a - each auxiliary field evaluated at the current point
1971 . a_t - the time derivative of each auxiliary field evaluated at the current point
1972 . a_x - the gradient of auxiliary each field evaluated at the current point
1973 . t - current time
1974 . x - coordinates of the current point
1975 . n - unit normal at the current point
1976 . numConstants - number of constant parameters
1977 . constants - constant parameters
1978 - f0 - output values at the current point
1979 
1980   Level: intermediate
1981 
1982 .seealso: PetscDSSetBdResidual()
1983 @*/
1984 PetscErrorCode PetscDSGetBdResidual(PetscDS prob, PetscInt f,
1985                                     void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1986                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1987                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1988                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
1989                                     void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1990                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1991                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1992                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
1993 {
1994   PetscFunctionBegin;
1995   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1996   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);
1997   if (f0) {PetscValidPointer(f0, 3); *f0 = prob->fBd[f*2+0];}
1998   if (f1) {PetscValidPointer(f1, 4); *f1 = prob->fBd[f*2+1];}
1999   PetscFunctionReturn(0);
2000 }
2001 
2002 /*@C
2003   PetscDSSetBdResidual - Get the pointwise boundary residual function for a given test field
2004 
2005   Not collective
2006 
2007   Input Parameters:
2008 + prob - The PetscDS
2009 . f    - The test field number
2010 . f0 - boundary integrand for the test function term
2011 - f1 - boundary integrand for the test function gradient term
2012 
2013   Note: We are using a first order FEM model for the weak form:
2014 
2015   \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
2016 
2017 The calling sequence for the callbacks f0 and f1 is given by:
2018 
2019 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2020 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2021 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2022 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
2023 
2024 + dim - the spatial dimension
2025 . Nf - the number of fields
2026 . uOff - the offset into u[] and u_t[] for each field
2027 . uOff_x - the offset into u_x[] for each field
2028 . u - each field evaluated at the current point
2029 . u_t - the time derivative of each field evaluated at the current point
2030 . u_x - the gradient of each field evaluated at the current point
2031 . aOff - the offset into a[] and a_t[] for each auxiliary field
2032 . aOff_x - the offset into a_x[] for each auxiliary field
2033 . a - each auxiliary field evaluated at the current point
2034 . a_t - the time derivative of each auxiliary field evaluated at the current point
2035 . a_x - the gradient of auxiliary each field evaluated at the current point
2036 . t - current time
2037 . x - coordinates of the current point
2038 . n - unit normal at the current point
2039 . numConstants - number of constant parameters
2040 . constants - constant parameters
2041 - f0 - output values at the current point
2042 
2043   Level: intermediate
2044 
2045 .seealso: PetscDSGetBdResidual()
2046 @*/
2047 PetscErrorCode PetscDSSetBdResidual(PetscDS prob, PetscInt f,
2048                                     void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2049                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2050                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2051                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]),
2052                                     void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2053                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2054                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2055                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]))
2056 {
2057   PetscErrorCode ierr;
2058 
2059   PetscFunctionBegin;
2060   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2061   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2062   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
2063   if (f0) {PetscValidFunction(f0, 3); prob->fBd[f*2+0] = f0;}
2064   if (f1) {PetscValidFunction(f1, 4); prob->fBd[f*2+1] = f1;}
2065   PetscFunctionReturn(0);
2066 }
2067 
2068 /*@
2069   PetscDSHasBdJacobian - Signals that boundary Jacobian functions have been set
2070 
2071   Not collective
2072 
2073   Input Parameter:
2074 . prob - The PetscDS
2075 
2076   Output Parameter:
2077 . hasBdJac - flag that pointwise function for the boundary Jacobian has been set
2078 
2079   Level: intermediate
2080 
2081 .seealso: PetscDSHasJacobian(), PetscDSSetBdJacobian(), PetscDSGetBdJacobian()
2082 @*/
2083 PetscErrorCode PetscDSHasBdJacobian(PetscDS prob, PetscBool *hasBdJac)
2084 {
2085   PetscInt f, g, h;
2086 
2087   PetscFunctionBegin;
2088   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2089   *hasBdJac = PETSC_FALSE;
2090   for (f = 0; f < prob->Nf; ++f) {
2091     for (g = 0; g < prob->Nf; ++g) {
2092       for (h = 0; h < 4; ++h) {
2093         if (prob->gBd[(f*prob->Nf + g)*4+h]) *hasBdJac = PETSC_TRUE;
2094       }
2095     }
2096   }
2097   PetscFunctionReturn(0);
2098 }
2099 
2100 /*@C
2101   PetscDSGetBdJacobian - Get the pointwise boundary Jacobian function for given test and basis field
2102 
2103   Not collective
2104 
2105   Input Parameters:
2106 + prob - The PetscDS
2107 . f    - The test field number
2108 - g    - The field number
2109 
2110   Output Parameters:
2111 + g0 - integrand for the test and basis function term
2112 . g1 - integrand for the test function and basis function gradient term
2113 . g2 - integrand for the test function gradient and basis function term
2114 - g3 - integrand for the test function gradient and basis function gradient term
2115 
2116   Note: We are using a first order FEM model for the weak form:
2117 
2118   \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
2119 
2120 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2121 
2122 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2123 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2124 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2125 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])
2126 
2127 + dim - the spatial dimension
2128 . Nf - the number of fields
2129 . uOff - the offset into u[] and u_t[] for each field
2130 . uOff_x - the offset into u_x[] for each field
2131 . u - each field evaluated at the current point
2132 . u_t - the time derivative of each field evaluated at the current point
2133 . u_x - the gradient of each field evaluated at the current point
2134 . aOff - the offset into a[] and a_t[] for each auxiliary field
2135 . aOff_x - the offset into a_x[] for each auxiliary field
2136 . a - each auxiliary field evaluated at the current point
2137 . a_t - the time derivative of each auxiliary field evaluated at the current point
2138 . a_x - the gradient of auxiliary each field evaluated at the current point
2139 . t - current time
2140 . u_tShift - the multiplier a for dF/dU_t
2141 . x - coordinates of the current point
2142 . n - normal at the current point
2143 . numConstants - number of constant parameters
2144 . constants - constant parameters
2145 - g0 - output values at the current point
2146 
2147   Level: intermediate
2148 
2149 .seealso: PetscDSSetBdJacobian()
2150 @*/
2151 PetscErrorCode PetscDSGetBdJacobian(PetscDS prob, PetscInt f, PetscInt g,
2152                                     void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2153                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2154                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2155                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2156                                     void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2157                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2158                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2159                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2160                                     void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2161                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2162                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2163                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2164                                     void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2165                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2166                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2167                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2168 {
2169   PetscFunctionBegin;
2170   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2171   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);
2172   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);
2173   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gBd[(f*prob->Nf + g)*4+0];}
2174   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gBd[(f*prob->Nf + g)*4+1];}
2175   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gBd[(f*prob->Nf + g)*4+2];}
2176   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gBd[(f*prob->Nf + g)*4+3];}
2177   PetscFunctionReturn(0);
2178 }
2179 
2180 /*@C
2181   PetscDSSetBdJacobian - Set the pointwise boundary Jacobian function for given test and basis field
2182 
2183   Not collective
2184 
2185   Input Parameters:
2186 + prob - The PetscDS
2187 . f    - The test field number
2188 . g    - The field number
2189 . g0 - integrand for the test and basis function term
2190 . g1 - integrand for the test function and basis function gradient term
2191 . g2 - integrand for the test function gradient and basis function term
2192 - g3 - integrand for the test function gradient and basis function gradient term
2193 
2194   Note: We are using a first order FEM model for the weak form:
2195 
2196   \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
2197 
2198 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2199 
2200 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2201 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2202 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2203 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])
2204 
2205 + dim - the spatial dimension
2206 . Nf - the number of fields
2207 . uOff - the offset into u[] and u_t[] for each field
2208 . uOff_x - the offset into u_x[] for each field
2209 . u - each field evaluated at the current point
2210 . u_t - the time derivative of each field evaluated at the current point
2211 . u_x - the gradient of each field evaluated at the current point
2212 . aOff - the offset into a[] and a_t[] for each auxiliary field
2213 . aOff_x - the offset into a_x[] for each auxiliary field
2214 . a - each auxiliary field evaluated at the current point
2215 . a_t - the time derivative of each auxiliary field evaluated at the current point
2216 . a_x - the gradient of auxiliary each field evaluated at the current point
2217 . t - current time
2218 . u_tShift - the multiplier a for dF/dU_t
2219 . x - coordinates of the current point
2220 . n - normal at the current point
2221 . numConstants - number of constant parameters
2222 . constants - constant parameters
2223 - g0 - output values at the current point
2224 
2225   Level: intermediate
2226 
2227 .seealso: PetscDSGetBdJacobian()
2228 @*/
2229 PetscErrorCode PetscDSSetBdJacobian(PetscDS prob, PetscInt f, PetscInt g,
2230                                     void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2231                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2232                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2233                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2234                                     void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2235                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2236                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2237                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2238                                     void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2239                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2240                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2241                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2242                                     void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2243                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2244                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2245                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2246 {
2247   PetscErrorCode ierr;
2248 
2249   PetscFunctionBegin;
2250   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2251   if (g0) PetscValidFunction(g0, 4);
2252   if (g1) PetscValidFunction(g1, 5);
2253   if (g2) PetscValidFunction(g2, 6);
2254   if (g3) PetscValidFunction(g3, 7);
2255   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2256   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
2257   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
2258   prob->gBd[(f*prob->Nf + g)*4+0] = g0;
2259   prob->gBd[(f*prob->Nf + g)*4+1] = g1;
2260   prob->gBd[(f*prob->Nf + g)*4+2] = g2;
2261   prob->gBd[(f*prob->Nf + g)*4+3] = g3;
2262   PetscFunctionReturn(0);
2263 }
2264 
2265 /*@
2266   PetscDSHasBdJacobianPreconditioner - Signals that boundary Jacobian preconditioner functions have been set
2267 
2268   Not collective
2269 
2270   Input Parameter:
2271 . prob - The PetscDS
2272 
2273   Output Parameter:
2274 . hasBdJac - flag that pointwise function for the boundary Jacobian preconditioner has been set
2275 
2276   Level: intermediate
2277 
2278 .seealso: PetscDSHasJacobian(), PetscDSSetBdJacobian(), PetscDSGetBdJacobian()
2279 @*/
2280 PetscErrorCode PetscDSHasBdJacobianPreconditioner(PetscDS prob, PetscBool *hasBdJacPre)
2281 {
2282   PetscInt f, g, h;
2283 
2284   PetscFunctionBegin;
2285   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2286   *hasBdJacPre = PETSC_FALSE;
2287   for (f = 0; f < prob->Nf; ++f) {
2288     for (g = 0; g < prob->Nf; ++g) {
2289       for (h = 0; h < 4; ++h) {
2290         if (prob->gpBd[(f*prob->Nf + g)*4+h]) *hasBdJacPre = PETSC_TRUE;
2291       }
2292     }
2293   }
2294   PetscFunctionReturn(0);
2295 }
2296 
2297 /*@C
2298   PetscDSGetBdJacobianPreconditioner - Get the pointwise boundary Jacobian preconditioner function for given test and basis field
2299 
2300   Not collective
2301 
2302   Input Parameters:
2303 + prob - The PetscDS
2304 . f    - The test field number
2305 - g    - The field number
2306 
2307   Output Parameters:
2308 + g0 - integrand for the test and basis function term
2309 . g1 - integrand for the test function and basis function gradient term
2310 . g2 - integrand for the test function gradient and basis function term
2311 - g3 - integrand for the test function gradient and basis function gradient term
2312 
2313   Note: We are using a first order FEM model for the weak form:
2314 
2315   \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
2316 
2317 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2318 
2319 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2320 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2321 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2322 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
2323 
2324 + dim - the spatial dimension
2325 . Nf - the number of fields
2326 . NfAux - the number of auxiliary fields
2327 . uOff - the offset into u[] and u_t[] for each field
2328 . uOff_x - the offset into u_x[] for each field
2329 . u - each field evaluated at the current point
2330 . u_t - the time derivative of each field evaluated at the current point
2331 . u_x - the gradient of each field evaluated at the current point
2332 . aOff - the offset into a[] and a_t[] for each auxiliary field
2333 . aOff_x - the offset into a_x[] for each auxiliary field
2334 . a - each auxiliary field evaluated at the current point
2335 . a_t - the time derivative of each auxiliary field evaluated at the current point
2336 . a_x - the gradient of auxiliary each field evaluated at the current point
2337 . t - current time
2338 . u_tShift - the multiplier a for dF/dU_t
2339 . x - coordinates of the current point
2340 . n - normal at the current point
2341 . numConstants - number of constant parameters
2342 . constants - constant parameters
2343 - g0 - output values at the current point
2344 
2345   This is not yet available in Fortran.
2346 
2347   Level: intermediate
2348 
2349 .seealso: PetscDSSetBdJacobianPreconditioner()
2350 @*/
2351 PetscErrorCode PetscDSGetBdJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
2352                                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2353                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2354                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2355                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2356                                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2357                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2358                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2359                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2360                                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2361                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2362                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2363                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2364                                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2365                                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2366                                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2367                                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2368 {
2369   PetscFunctionBegin;
2370   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2371   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);
2372   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);
2373   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gpBd[(f*prob->Nf + g)*4+0];}
2374   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gpBd[(f*prob->Nf + g)*4+1];}
2375   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gpBd[(f*prob->Nf + g)*4+2];}
2376   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gpBd[(f*prob->Nf + g)*4+3];}
2377   PetscFunctionReturn(0);
2378 }
2379 
2380 /*@C
2381   PetscDSSetBdJacobianPreconditioner - Set the pointwise boundary Jacobian preconditioner function for given test and basis field
2382 
2383   Not collective
2384 
2385   Input Parameters:
2386 + prob - The PetscDS
2387 . f    - The test field number
2388 . g    - The field number
2389 . g0 - integrand for the test and basis function term
2390 . g1 - integrand for the test function and basis function gradient term
2391 . g2 - integrand for the test function gradient and basis function term
2392 - g3 - integrand for the test function gradient and basis function gradient term
2393 
2394   Note: We are using a first order FEM model for the weak form:
2395 
2396   \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
2397 
2398 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
2399 
2400 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2401 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2402 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2403 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[])
2404 
2405 + dim - the spatial dimension
2406 . Nf - the number of fields
2407 . NfAux - the number of auxiliary fields
2408 . uOff - the offset into u[] and u_t[] for each field
2409 . uOff_x - the offset into u_x[] for each field
2410 . u - each field evaluated at the current point
2411 . u_t - the time derivative of each field evaluated at the current point
2412 . u_x - the gradient of each field evaluated at the current point
2413 . aOff - the offset into a[] and a_t[] for each auxiliary field
2414 . aOff_x - the offset into a_x[] for each auxiliary field
2415 . a - each auxiliary field evaluated at the current point
2416 . a_t - the time derivative of each auxiliary field evaluated at the current point
2417 . a_x - the gradient of auxiliary each field evaluated at the current point
2418 . t - current time
2419 . u_tShift - the multiplier a for dF/dU_t
2420 . x - coordinates of the current point
2421 . n - normal at the current point
2422 . numConstants - number of constant parameters
2423 . constants - constant parameters
2424 - g0 - output values at the current point
2425 
2426   This is not yet available in Fortran.
2427 
2428   Level: intermediate
2429 
2430 .seealso: PetscDSGetBdJacobianPreconditioner()
2431 @*/
2432 PetscErrorCode PetscDSSetBdJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
2433                                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2434                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2435                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2436                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]),
2437                                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2438                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2439                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2440                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]),
2441                                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2442                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2443                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2444                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]),
2445                                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2446                                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2447                                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2448                                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]))
2449 {
2450   PetscErrorCode ierr;
2451 
2452   PetscFunctionBegin;
2453   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2454   if (g0) PetscValidFunction(g0, 4);
2455   if (g1) PetscValidFunction(g1, 5);
2456   if (g2) PetscValidFunction(g2, 6);
2457   if (g3) PetscValidFunction(g3, 7);
2458   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2459   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
2460   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
2461   prob->gpBd[(f*prob->Nf + g)*4+0] = g0;
2462   prob->gpBd[(f*prob->Nf + g)*4+1] = g1;
2463   prob->gpBd[(f*prob->Nf + g)*4+2] = g2;
2464   prob->gpBd[(f*prob->Nf + g)*4+3] = g3;
2465   PetscFunctionReturn(0);
2466 }
2467 
2468 /*@C
2469   PetscDSGetExactSolution - Get the pointwise exact solution function for a given test field
2470 
2471   Not collective
2472 
2473   Input Parameters:
2474 + prob - The PetscDS
2475 - f    - The test field number
2476 
2477   Output Parameter:
2478 + exactSol - exact solution for the test field
2479 - exactCtx - exact solution context
2480 
2481   Note: The calling sequence for the solution functions is given by:
2482 
2483 $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2484 
2485 + dim - the spatial dimension
2486 . t - current time
2487 . x - coordinates of the current point
2488 . Nc - the number of field components
2489 . u - the solution field evaluated at the current point
2490 - ctx - a user context
2491 
2492   Level: intermediate
2493 
2494 .seealso: PetscDSSetExactSolution()
2495 @*/
2496 PetscErrorCode PetscDSGetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (**sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void **ctx)
2497 {
2498   PetscFunctionBegin;
2499   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2500   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);
2501   if (sol) {PetscValidPointer(sol, 3); *sol = prob->exactSol[f];}
2502   if (ctx) {PetscValidPointer(ctx, 4); *ctx = prob->exactCtx[f];}
2503   PetscFunctionReturn(0);
2504 }
2505 
2506 /*@C
2507   PetscDSSetExactSolution - Set the pointwise exact solution function for a given test field
2508 
2509   Not collective
2510 
2511   Input Parameters:
2512 + prob - The PetscDS
2513 . f    - The test field number
2514 . sol  - solution function for the test fields
2515 - ctx  - solution context or NULL
2516 
2517   Note: The calling sequence for solution functions is given by:
2518 
2519 $ sol(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx)
2520 
2521 + dim - the spatial dimension
2522 . t - current time
2523 . x - coordinates of the current point
2524 . Nc - the number of field components
2525 . u - the solution field evaluated at the current point
2526 - ctx - a user context
2527 
2528   Level: intermediate
2529 
2530 .seealso: PetscDSGetExactSolution()
2531 @*/
2532 PetscErrorCode PetscDSSetExactSolution(PetscDS prob, PetscInt f, PetscErrorCode (*sol)(PetscInt dim, PetscReal t, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx), void *ctx)
2533 {
2534   PetscErrorCode ierr;
2535 
2536   PetscFunctionBegin;
2537   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2538   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2539   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
2540   if (sol) {PetscValidFunction(sol, 3); prob->exactSol[f] = sol;}
2541   if (ctx) {PetscValidFunction(ctx, 4); prob->exactCtx[f] = ctx;}
2542   PetscFunctionReturn(0);
2543 }
2544 
2545 /*@C
2546   PetscDSGetConstants - Returns the array of constants passed to point functions
2547 
2548   Not collective
2549 
2550   Input Parameter:
2551 . prob - The PetscDS object
2552 
2553   Output Parameters:
2554 + numConstants - The number of constants
2555 - constants    - The array of constants, NULL if there are none
2556 
2557   Level: intermediate
2558 
2559 .seealso: PetscDSSetConstants(), PetscDSCreate()
2560 @*/
2561 PetscErrorCode PetscDSGetConstants(PetscDS prob, PetscInt *numConstants, const PetscScalar *constants[])
2562 {
2563   PetscFunctionBegin;
2564   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2565   if (numConstants) {PetscValidPointer(numConstants, 2); *numConstants = prob->numConstants;}
2566   if (constants)    {PetscValidPointer(constants, 3);    *constants    = prob->constants;}
2567   PetscFunctionReturn(0);
2568 }
2569 
2570 /*@C
2571   PetscDSSetConstants - Set the array of constants passed to point functions
2572 
2573   Not collective
2574 
2575   Input Parameters:
2576 + prob         - The PetscDS object
2577 . numConstants - The number of constants
2578 - constants    - The array of constants, NULL if there are none
2579 
2580   Level: intermediate
2581 
2582 .seealso: PetscDSGetConstants(), PetscDSCreate()
2583 @*/
2584 PetscErrorCode PetscDSSetConstants(PetscDS prob, PetscInt numConstants, PetscScalar constants[])
2585 {
2586   PetscErrorCode ierr;
2587 
2588   PetscFunctionBegin;
2589   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2590   if (numConstants != prob->numConstants) {
2591     ierr = PetscFree(prob->constants);CHKERRQ(ierr);
2592     prob->numConstants = numConstants;
2593     if (prob->numConstants) {
2594       ierr = PetscMalloc1(prob->numConstants, &prob->constants);CHKERRQ(ierr);
2595     } else {
2596       prob->constants = NULL;
2597     }
2598   }
2599   if (prob->numConstants) {
2600     PetscValidPointer(constants, 3);
2601     ierr = PetscArraycpy(prob->constants, constants, prob->numConstants);CHKERRQ(ierr);
2602   }
2603   PetscFunctionReturn(0);
2604 }
2605 
2606 /*@
2607   PetscDSGetFieldIndex - Returns the index of the given field
2608 
2609   Not collective
2610 
2611   Input Parameters:
2612 + prob - The PetscDS object
2613 - disc - The discretization object
2614 
2615   Output Parameter:
2616 . f - The field number
2617 
2618   Level: beginner
2619 
2620 .seealso: PetscGetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
2621 @*/
2622 PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
2623 {
2624   PetscInt g;
2625 
2626   PetscFunctionBegin;
2627   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2628   PetscValidPointer(f, 3);
2629   *f = -1;
2630   for (g = 0; g < prob->Nf; ++g) {if (disc == prob->disc[g]) break;}
2631   if (g == prob->Nf) SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
2632   *f = g;
2633   PetscFunctionReturn(0);
2634 }
2635 
2636 /*@
2637   PetscDSGetFieldSize - Returns the size of the given field in the full space basis
2638 
2639   Not collective
2640 
2641   Input Parameters:
2642 + prob - The PetscDS object
2643 - f - The field number
2644 
2645   Output Parameter:
2646 . size - The size
2647 
2648   Level: beginner
2649 
2650 .seealso: PetscDSGetFieldOffset(), PetscDSGetNumFields(), PetscDSCreate()
2651 @*/
2652 PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
2653 {
2654   PetscErrorCode ierr;
2655 
2656   PetscFunctionBegin;
2657   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2658   PetscValidPointer(size, 3);
2659   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);
2660   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2661   *size = prob->Nb[f];
2662   PetscFunctionReturn(0);
2663 }
2664 
2665 /*@
2666   PetscDSGetFieldOffset - Returns the offset of the given field in the full space basis
2667 
2668   Not collective
2669 
2670   Input Parameters:
2671 + prob - The PetscDS object
2672 - f - The field number
2673 
2674   Output Parameter:
2675 . off - The offset
2676 
2677   Level: beginner
2678 
2679 .seealso: PetscDSGetFieldSize(), PetscDSGetNumFields(), PetscDSCreate()
2680 @*/
2681 PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
2682 {
2683   PetscInt       size, g;
2684   PetscErrorCode ierr;
2685 
2686   PetscFunctionBegin;
2687   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2688   PetscValidPointer(off, 3);
2689   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);
2690   *off = 0;
2691   for (g = 0; g < f; ++g) {
2692     ierr = PetscDSGetFieldSize(prob, g, &size);CHKERRQ(ierr);
2693     *off += size;
2694   }
2695   PetscFunctionReturn(0);
2696 }
2697 
2698 /*@
2699   PetscDSGetDimensions - Returns the size of the approximation space for each field on an evaluation point
2700 
2701   Not collective
2702 
2703   Input Parameter:
2704 . prob - The PetscDS object
2705 
2706   Output Parameter:
2707 . dimensions - The number of dimensions
2708 
2709   Level: beginner
2710 
2711 .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
2712 @*/
2713 PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
2714 {
2715   PetscErrorCode ierr;
2716 
2717   PetscFunctionBegin;
2718   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2719   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2720   PetscValidPointer(dimensions, 2);
2721   *dimensions = prob->Nb;
2722   PetscFunctionReturn(0);
2723 }
2724 
2725 /*@
2726   PetscDSGetComponents - Returns the number of components for each field on an evaluation point
2727 
2728   Not collective
2729 
2730   Input Parameter:
2731 . prob - The PetscDS object
2732 
2733   Output Parameter:
2734 . components - The number of components
2735 
2736   Level: beginner
2737 
2738 .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
2739 @*/
2740 PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
2741 {
2742   PetscErrorCode ierr;
2743 
2744   PetscFunctionBegin;
2745   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2746   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2747   PetscValidPointer(components, 2);
2748   *components = prob->Nc;
2749   PetscFunctionReturn(0);
2750 }
2751 
2752 /*@
2753   PetscDSGetComponentOffset - Returns the offset of the given field on an evaluation point
2754 
2755   Not collective
2756 
2757   Input Parameters:
2758 + prob - The PetscDS object
2759 - f - The field number
2760 
2761   Output Parameter:
2762 . off - The offset
2763 
2764   Level: beginner
2765 
2766 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2767 @*/
2768 PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
2769 {
2770   PetscFunctionBegin;
2771   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2772   PetscValidPointer(off, 3);
2773   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);
2774   *off = prob->off[f];
2775   PetscFunctionReturn(0);
2776 }
2777 
2778 /*@
2779   PetscDSGetComponentOffsets - Returns the offset of each field on an evaluation point
2780 
2781   Not collective
2782 
2783   Input Parameter:
2784 . prob - The PetscDS object
2785 
2786   Output Parameter:
2787 . offsets - The offsets
2788 
2789   Level: beginner
2790 
2791 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2792 @*/
2793 PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
2794 {
2795   PetscFunctionBegin;
2796   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2797   PetscValidPointer(offsets, 2);
2798   *offsets = prob->off;
2799   PetscFunctionReturn(0);
2800 }
2801 
2802 /*@
2803   PetscDSGetComponentDerivativeOffsets - Returns the offset of each field derivative on an evaluation point
2804 
2805   Not collective
2806 
2807   Input Parameter:
2808 . prob - The PetscDS object
2809 
2810   Output Parameter:
2811 . offsets - The offsets
2812 
2813   Level: beginner
2814 
2815 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2816 @*/
2817 PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
2818 {
2819   PetscFunctionBegin;
2820   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2821   PetscValidPointer(offsets, 2);
2822   *offsets = prob->offDer;
2823   PetscFunctionReturn(0);
2824 }
2825 
2826 /*@C
2827   PetscDSGetTabulation - Return the basis tabulation at quadrature points for the volume discretization
2828 
2829   Not collective
2830 
2831   Input Parameter:
2832 . prob - The PetscDS object
2833 
2834   Output Parameter:
2835 . T - The basis function and derivatives tabulation at quadrature points for each field
2836 
2837   Level: intermediate
2838 
2839 .seealso: PetscDSCreate()
2840 @*/
2841 PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscTabulation *T[])
2842 {
2843   PetscErrorCode ierr;
2844 
2845   PetscFunctionBegin;
2846   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2847   PetscValidPointer(T, 2);
2848   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2849   *T = prob->T;
2850   PetscFunctionReturn(0);
2851 }
2852 
2853 /*@C
2854   PetscDSGetFaceTabulation - Return the basis tabulation at quadrature points on the faces
2855 
2856   Not collective
2857 
2858   Input Parameter:
2859 . prob - The PetscDS object
2860 
2861   Output Parameter:
2862 . Tf - The basis function and derviative tabulation on each lcoal face at quadrature points for each and field
2863 
2864   Level: intermediate
2865 
2866 .seealso: PetscDSGetTabulation(), PetscDSCreate()
2867 @*/
2868 PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscTabulation *Tf[])
2869 {
2870   PetscErrorCode ierr;
2871 
2872   PetscFunctionBegin;
2873   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2874   PetscValidPointer(Tf, 2);
2875   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2876   *Tf = prob->Tf;
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
2881 {
2882   PetscErrorCode ierr;
2883 
2884   PetscFunctionBegin;
2885   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2886   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2887   if (u)   {PetscValidPointer(u, 2);   *u   = prob->u;}
2888   if (u_t) {PetscValidPointer(u_t, 3); *u_t = prob->u_t;}
2889   if (u_x) {PetscValidPointer(u_x, 4); *u_x = prob->u_x;}
2890   PetscFunctionReturn(0);
2891 }
2892 
2893 PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar **f0, PetscScalar **f1, PetscScalar **g0, PetscScalar **g1, PetscScalar **g2, PetscScalar **g3)
2894 {
2895   PetscErrorCode ierr;
2896 
2897   PetscFunctionBegin;
2898   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2899   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2900   if (f0) {PetscValidPointer(f0, 2); *f0 = prob->f0;}
2901   if (f1) {PetscValidPointer(f1, 3); *f1 = prob->f1;}
2902   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->g0;}
2903   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->g1;}
2904   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->g2;}
2905   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->g3;}
2906   PetscFunctionReturn(0);
2907 }
2908 
2909 PetscErrorCode PetscDSGetWorkspace(PetscDS prob, PetscReal **x, PetscScalar **basisReal, PetscScalar **basisDerReal, PetscScalar **testReal, PetscScalar **testDerReal)
2910 {
2911   PetscErrorCode ierr;
2912 
2913   PetscFunctionBegin;
2914   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2915   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2916   if (x)            {PetscValidPointer(x, 2);            *x            = prob->x;}
2917   if (basisReal)    {PetscValidPointer(basisReal, 3);    *basisReal    = prob->basisReal;}
2918   if (basisDerReal) {PetscValidPointer(basisDerReal, 4); *basisDerReal = prob->basisDerReal;}
2919   if (testReal)     {PetscValidPointer(testReal, 5);     *testReal     = prob->testReal;}
2920   if (testDerReal)  {PetscValidPointer(testDerReal, 6);  *testDerReal  = prob->testDerReal;}
2921   PetscFunctionReturn(0);
2922 }
2923 
2924 /*@C
2925   PetscDSAddBoundary - Add a boundary condition to the model
2926 
2927   Collective on ds
2928 
2929   Input Parameters:
2930 + ds          - The PetscDS object
2931 . type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
2932 . name        - The BC name
2933 . labelname   - The label defining constrained points
2934 . field       - The field to constrain
2935 . numcomps    - The number of constrained field components (0 will constrain all fields)
2936 . comps       - An array of constrained component numbers
2937 . bcFunc      - A pointwise function giving boundary values
2938 . numids      - The number of DMLabel ids for constrained points
2939 . ids         - An array of ids for constrained points
2940 - ctx         - An optional user context for bcFunc
2941 
2942   Options Database Keys:
2943 + -bc_<boundary name> <num> - Overrides the boundary ids
2944 - -bc_<boundary name>_comp <num> - Overrides the boundary components
2945 
2946   Level: developer
2947 
2948 .seealso: PetscDSGetBoundary()
2949 @*/
2950 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)
2951 {
2952   DSBoundary     b;
2953   PetscErrorCode ierr;
2954 
2955   PetscFunctionBegin;
2956   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2957   PetscValidLogicalCollectiveEnum(ds, type, 2);
2958   PetscValidLogicalCollectiveInt(ds, field, 5);
2959   PetscValidLogicalCollectiveInt(ds, numcomps, 6);
2960   PetscValidLogicalCollectiveInt(ds, numids, 9);
2961   ierr = PetscNew(&b);CHKERRQ(ierr);
2962   ierr = PetscStrallocpy(name, (char **) &b->name);CHKERRQ(ierr);
2963   ierr = PetscStrallocpy(labelname, (char **) &b->labelname);CHKERRQ(ierr);
2964   ierr = PetscMalloc1(numcomps, &b->comps);CHKERRQ(ierr);
2965   if (numcomps) {ierr = PetscArraycpy(b->comps, comps, numcomps);CHKERRQ(ierr);}
2966   ierr = PetscMalloc1(numids, &b->ids);CHKERRQ(ierr);
2967   if (numids) {ierr = PetscArraycpy(b->ids, ids, numids);CHKERRQ(ierr);}
2968   b->type            = type;
2969   b->field           = field;
2970   b->numcomps        = numcomps;
2971   b->func            = bcFunc;
2972   b->numids          = numids;
2973   b->ctx             = ctx;
2974   b->next            = ds->boundary;
2975   ds->boundary       = b;
2976   PetscFunctionReturn(0);
2977 }
2978 
2979 /*@C
2980   PetscDSUpdateBoundary - Change a boundary condition for the model
2981 
2982   Input Parameters:
2983 + ds          - The PetscDS object
2984 . bd          - The boundary condition number
2985 . type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
2986 . name        - The BC name
2987 . labelname   - The label defining constrained points
2988 . field       - The field to constrain
2989 . numcomps    - The number of constrained field components
2990 . comps       - An array of constrained component numbers
2991 . bcFunc      - A pointwise function giving boundary values
2992 . numids      - The number of DMLabel ids for constrained points
2993 . ids         - An array of ids for constrained points
2994 - ctx         - An optional user context for bcFunc
2995 
2996   Note: The boundary condition number is the order in which it was registered. The user can get the number of boundary conditions from PetscDSGetNumBoundary().
2997 
2998   Level: developer
2999 
3000 .seealso: PetscDSAddBoundary(), PetscDSGetBoundary(), PetscDSGetNumBoundary()
3001 @*/
3002 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)
3003 {
3004   DSBoundary     b = ds->boundary;
3005   PetscInt       n = 0;
3006   PetscErrorCode ierr;
3007 
3008   PetscFunctionBegin;
3009   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3010   while (b) {
3011     if (n == bd) break;
3012     b = b->next;
3013     ++n;
3014   }
3015   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
3016   if (name) {
3017     ierr = PetscFree(b->name);CHKERRQ(ierr);
3018     ierr = PetscStrallocpy(name, (char **) &b->name);CHKERRQ(ierr);
3019   }
3020   if (labelname) {
3021     ierr = PetscFree(b->labelname);CHKERRQ(ierr);
3022     ierr = PetscStrallocpy(labelname, (char **) &b->labelname);CHKERRQ(ierr);
3023   }
3024   if (numcomps >= 0 && numcomps != b->numcomps) {
3025     b->numcomps = numcomps;
3026     ierr = PetscFree(b->comps);CHKERRQ(ierr);
3027     ierr = PetscMalloc1(numcomps, &b->comps);CHKERRQ(ierr);
3028     if (numcomps) {ierr = PetscArraycpy(b->comps, comps, numcomps);CHKERRQ(ierr);}
3029   }
3030   if (numids >= 0 && numids != b->numids) {
3031     b->numids = numids;
3032     ierr = PetscFree(b->ids);CHKERRQ(ierr);
3033     ierr = PetscMalloc1(numids, &b->ids);CHKERRQ(ierr);
3034     if (numids) {ierr = PetscArraycpy(b->ids, ids, numids);CHKERRQ(ierr);}
3035   }
3036   b->type = type;
3037   if (field >= 0) {b->field  = field;}
3038   if (bcFunc)     {b->func   = bcFunc;}
3039   if (ctx)        {b->ctx    = ctx;}
3040   PetscFunctionReturn(0);
3041 }
3042 
3043 /*@
3044   PetscDSGetNumBoundary - Get the number of registered BC
3045 
3046   Input Parameters:
3047 . ds - The PetscDS object
3048 
3049   Output Parameters:
3050 . numBd - The number of BC
3051 
3052   Level: intermediate
3053 
3054 .seealso: PetscDSAddBoundary(), PetscDSGetBoundary()
3055 @*/
3056 PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
3057 {
3058   DSBoundary b = ds->boundary;
3059 
3060   PetscFunctionBegin;
3061   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3062   PetscValidPointer(numBd, 2);
3063   *numBd = 0;
3064   while (b) {++(*numBd); b = b->next;}
3065   PetscFunctionReturn(0);
3066 }
3067 
3068 /*@C
3069   PetscDSGetBoundary - Gets a boundary condition to the model
3070 
3071   Input Parameters:
3072 + ds          - The PetscDS object
3073 - bd          - The BC number
3074 
3075   Output Parameters:
3076 + type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
3077 . name        - The BC name
3078 . labelname   - The label defining constrained points
3079 . field       - The field to constrain
3080 . numcomps    - The number of constrained field components
3081 . comps       - An array of constrained component numbers
3082 . bcFunc      - A pointwise function giving boundary values
3083 . numids      - The number of DMLabel ids for constrained points
3084 . ids         - An array of ids for constrained points
3085 - ctx         - An optional user context for bcFunc
3086 
3087   Options Database Keys:
3088 + -bc_<boundary name> <num> - Overrides the boundary ids
3089 - -bc_<boundary name>_comp <num> - Overrides the boundary components
3090 
3091   Level: developer
3092 
3093 .seealso: PetscDSAddBoundary()
3094 @*/
3095 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)
3096 {
3097   DSBoundary b    = ds->boundary;
3098   PetscInt   n    = 0;
3099 
3100   PetscFunctionBegin;
3101   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3102   while (b) {
3103     if (n == bd) break;
3104     b = b->next;
3105     ++n;
3106   }
3107   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
3108   if (type) {
3109     PetscValidPointer(type, 3);
3110     *type = b->type;
3111   }
3112   if (name) {
3113     PetscValidPointer(name, 4);
3114     *name = b->name;
3115   }
3116   if (labelname) {
3117     PetscValidPointer(labelname, 5);
3118     *labelname = b->labelname;
3119   }
3120   if (field) {
3121     PetscValidPointer(field, 6);
3122     *field = b->field;
3123   }
3124   if (numcomps) {
3125     PetscValidPointer(numcomps, 7);
3126     *numcomps = b->numcomps;
3127   }
3128   if (comps) {
3129     PetscValidPointer(comps, 8);
3130     *comps = b->comps;
3131   }
3132   if (func) {
3133     PetscValidPointer(func, 9);
3134     *func = b->func;
3135   }
3136   if (numids) {
3137     PetscValidPointer(numids, 10);
3138     *numids = b->numids;
3139   }
3140   if (ids) {
3141     PetscValidPointer(ids, 11);
3142     *ids = b->ids;
3143   }
3144   if (ctx) {
3145     PetscValidPointer(ctx, 12);
3146     *ctx = b->ctx;
3147   }
3148   PetscFunctionReturn(0);
3149 }
3150 
3151 /*@
3152   PetscDSCopyBoundary - Copy all boundary condition objects to the new problem
3153 
3154   Not collective
3155 
3156   Input Parameter:
3157 . prob - The PetscDS object
3158 
3159   Output Parameter:
3160 . newprob - The PetscDS copy
3161 
3162   Level: intermediate
3163 
3164 .seealso: PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3165 @*/
3166 PetscErrorCode PetscDSCopyBoundary(PetscDS probA, PetscDS probB)
3167 {
3168   DSBoundary     b, next, *lastnext;
3169   PetscErrorCode ierr;
3170 
3171   PetscFunctionBegin;
3172   PetscValidHeaderSpecific(probA, PETSCDS_CLASSID, 1);
3173   PetscValidHeaderSpecific(probB, PETSCDS_CLASSID, 2);
3174   if (probA == probB) PetscFunctionReturn(0);
3175   next = probB->boundary;
3176   while (next) {
3177     DSBoundary b = next;
3178 
3179     next = b->next;
3180     ierr = PetscFree(b->comps);CHKERRQ(ierr);
3181     ierr = PetscFree(b->ids);CHKERRQ(ierr);
3182     ierr = PetscFree(b->name);CHKERRQ(ierr);
3183     ierr = PetscFree(b->labelname);CHKERRQ(ierr);
3184     ierr = PetscFree(b);CHKERRQ(ierr);
3185   }
3186   lastnext = &(probB->boundary);
3187   for (b = probA->boundary; b; b = b->next) {
3188     DSBoundary bNew;
3189 
3190     ierr = PetscNew(&bNew);CHKERRQ(ierr);
3191     bNew->numcomps = b->numcomps;
3192     ierr = PetscMalloc1(bNew->numcomps, &bNew->comps);CHKERRQ(ierr);
3193     ierr = PetscArraycpy(bNew->comps, b->comps, bNew->numcomps);CHKERRQ(ierr);
3194     bNew->numids = b->numids;
3195     ierr = PetscMalloc1(bNew->numids, &bNew->ids);CHKERRQ(ierr);
3196     ierr = PetscArraycpy(bNew->ids, b->ids, bNew->numids);CHKERRQ(ierr);
3197     ierr = PetscStrallocpy(b->labelname,(char **) &(bNew->labelname));CHKERRQ(ierr);
3198     ierr = PetscStrallocpy(b->name,(char **) &(bNew->name));CHKERRQ(ierr);
3199     bNew->ctx   = b->ctx;
3200     bNew->type  = b->type;
3201     bNew->field = b->field;
3202     bNew->func  = b->func;
3203 
3204     *lastnext = bNew;
3205     lastnext = &(bNew->next);
3206   }
3207   PetscFunctionReturn(0);
3208 }
3209 
3210 /*@C
3211   PetscDSSelectEquations - Copy pointwise function pointers to the new problem with different field layout
3212 
3213   Not collective
3214 
3215   Input Parameter:
3216 + prob - The PetscDS object
3217 . numFields - Number of new fields
3218 - fields - Old field number for each new field
3219 
3220   Output Parameter:
3221 . newprob - The PetscDS copy
3222 
3223   Level: intermediate
3224 
3225 .seealso: PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3226 @*/
3227 PetscErrorCode PetscDSSelectEquations(PetscDS prob, PetscInt numFields, const PetscInt fields[], PetscDS newprob)
3228 {
3229   PetscInt       Nf, Nfn, fn, gn;
3230   PetscErrorCode ierr;
3231 
3232   PetscFunctionBegin;
3233   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3234   if (fields) PetscValidPointer(fields, 3);
3235   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 4);
3236   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
3237   ierr = PetscDSGetNumFields(newprob, &Nfn);CHKERRQ(ierr);
3238   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);
3239   for (fn = 0; fn < numFields; ++fn) {
3240     const PetscInt   f = fields ? fields[fn] : fn;
3241     PetscPointFunc   obj;
3242     PetscPointFunc   f0, f1;
3243     PetscBdPointFunc f0Bd, f1Bd;
3244     PetscRiemannFunc r;
3245 
3246     if (f >= Nf) continue;
3247     ierr = PetscDSGetObjective(prob, f, &obj);CHKERRQ(ierr);
3248     ierr = PetscDSGetResidual(prob, f, &f0, &f1);CHKERRQ(ierr);
3249     ierr = PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd);CHKERRQ(ierr);
3250     ierr = PetscDSGetRiemannSolver(prob, f, &r);CHKERRQ(ierr);
3251     ierr = PetscDSSetObjective(newprob, fn, obj);CHKERRQ(ierr);
3252     ierr = PetscDSSetResidual(newprob, fn, f0, f1);CHKERRQ(ierr);
3253     ierr = PetscDSSetBdResidual(newprob, fn, f0Bd, f1Bd);CHKERRQ(ierr);
3254     ierr = PetscDSSetRiemannSolver(newprob, fn, r);CHKERRQ(ierr);
3255     for (gn = 0; gn < numFields; ++gn) {
3256       const PetscInt  g = fields ? fields[gn] : gn;
3257       PetscPointJac   g0, g1, g2, g3;
3258       PetscPointJac   g0p, g1p, g2p, g3p;
3259       PetscBdPointJac g0Bd, g1Bd, g2Bd, g3Bd;
3260 
3261       if (g >= Nf) continue;
3262       ierr = PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3);CHKERRQ(ierr);
3263       ierr = PetscDSGetJacobianPreconditioner(prob, f, g, &g0p, &g1p, &g2p, &g3p);CHKERRQ(ierr);
3264       ierr = PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd);CHKERRQ(ierr);
3265       ierr = PetscDSSetJacobian(newprob, fn, gn, g0, g1, g2, g3);CHKERRQ(ierr);
3266       ierr = PetscDSSetJacobianPreconditioner(prob, fn, gn, g0p, g1p, g2p, g3p);CHKERRQ(ierr);
3267       ierr = PetscDSSetBdJacobian(newprob, fn, gn, g0Bd, g1Bd, g2Bd, g3Bd);CHKERRQ(ierr);
3268     }
3269   }
3270   PetscFunctionReturn(0);
3271 }
3272 
3273 /*@
3274   PetscDSCopyEquations - Copy all pointwise function pointers to the new problem
3275 
3276   Not collective
3277 
3278   Input Parameter:
3279 . prob - The PetscDS object
3280 
3281   Output Parameter:
3282 . newprob - The PetscDS copy
3283 
3284   Level: intermediate
3285 
3286 .seealso: PetscDSCopyBoundary(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3287 @*/
3288 PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
3289 {
3290   PetscInt       Nf, Ng;
3291   PetscErrorCode ierr;
3292 
3293   PetscFunctionBegin;
3294   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3295   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
3296   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
3297   ierr = PetscDSGetNumFields(newprob, &Ng);CHKERRQ(ierr);
3298   if (Nf != Ng) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %D != %D", Nf, Ng);
3299   ierr = PetscDSSelectEquations(prob, Nf, NULL, newprob);CHKERRQ(ierr);
3300   PetscFunctionReturn(0);
3301 }
3302 /*@
3303   PetscDSCopyConstants - Copy all constants to the new problem
3304 
3305   Not collective
3306 
3307   Input Parameter:
3308 . prob - The PetscDS object
3309 
3310   Output Parameter:
3311 . newprob - The PetscDS copy
3312 
3313   Level: intermediate
3314 
3315 .seealso: PetscDSCopyBoundary(), PetscDSCopyEquations(), PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
3316 @*/
3317 PetscErrorCode PetscDSCopyConstants(PetscDS prob, PetscDS newprob)
3318 {
3319   PetscInt           Nc;
3320   const PetscScalar *constants;
3321   PetscErrorCode     ierr;
3322 
3323   PetscFunctionBegin;
3324   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3325   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
3326   ierr = PetscDSGetConstants(prob, &Nc, &constants);CHKERRQ(ierr);
3327   ierr = PetscDSSetConstants(newprob, Nc, (PetscScalar *) constants);CHKERRQ(ierr);
3328   PetscFunctionReturn(0);
3329 }
3330 
3331 PetscErrorCode PetscDSGetHeightSubspace(PetscDS prob, PetscInt height, PetscDS *subprob)
3332 {
3333   PetscInt       dim, Nf, f;
3334   PetscErrorCode ierr;
3335 
3336   PetscFunctionBegin;
3337   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3338   PetscValidPointer(subprob, 3);
3339   if (height == 0) {*subprob = prob; PetscFunctionReturn(0);}
3340   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
3341   ierr = PetscDSGetSpatialDimension(prob, &dim);CHKERRQ(ierr);
3342   if (height > dim) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_OUTOFRANGE, "DS can only handle height in [0, %D], not %D", dim, height);
3343   if (!prob->subprobs) {ierr = PetscCalloc1(dim, &prob->subprobs);CHKERRQ(ierr);}
3344   if (!prob->subprobs[height-1]) {
3345     PetscInt cdim;
3346 
3347     ierr = PetscDSCreate(PetscObjectComm((PetscObject) prob), &prob->subprobs[height-1]);CHKERRQ(ierr);
3348     ierr = PetscDSGetCoordinateDimension(prob, &cdim);CHKERRQ(ierr);
3349     ierr = PetscDSSetCoordinateDimension(prob->subprobs[height-1], cdim);CHKERRQ(ierr);
3350     for (f = 0; f < Nf; ++f) {
3351       PetscFE      subfe;
3352       PetscObject  obj;
3353       PetscClassId id;
3354 
3355       ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
3356       ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
3357       if (id == PETSCFE_CLASSID) {ierr = PetscFEGetHeightSubspace((PetscFE) obj, height, &subfe);CHKERRQ(ierr);}
3358       else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unsupported discretization type for field %d", f);
3359       ierr = PetscDSSetDiscretization(prob->subprobs[height-1], f, (PetscObject) subfe);CHKERRQ(ierr);
3360     }
3361   }
3362   *subprob = prob->subprobs[height-1];
3363   PetscFunctionReturn(0);
3364 }
3365 
3366 PetscErrorCode PetscDSIsFE_Internal(PetscDS ds, PetscInt f, PetscBool *isFE)
3367 {
3368   PetscObject    obj;
3369   PetscClassId   id;
3370   PetscInt       Nf;
3371   PetscErrorCode ierr;
3372 
3373   PetscFunctionBegin;
3374   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
3375   PetscValidPointer(isFE, 3);
3376   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
3377   if (f >= Nf) SETERRQ2(PetscObjectComm((PetscObject) ds), PETSC_ERR_ARG_SIZ, "Field %D must be in [0, %D)", f, Nf);
3378   ierr = PetscDSGetDiscretization(ds, f, &obj);CHKERRQ(ierr);
3379   ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
3380   if (id == PETSCFE_CLASSID) *isFE = PETSC_TRUE;
3381   else                       *isFE = PETSC_FALSE;
3382   PetscFunctionReturn(0);
3383 }
3384 
3385 static PetscErrorCode PetscDSDestroy_Basic(PetscDS prob)
3386 {
3387   PetscErrorCode      ierr;
3388 
3389   PetscFunctionBegin;
3390   ierr = PetscFree(prob->data);CHKERRQ(ierr);
3391   PetscFunctionReturn(0);
3392 }
3393 
3394 static PetscErrorCode PetscDSInitialize_Basic(PetscDS prob)
3395 {
3396   PetscFunctionBegin;
3397   prob->ops->setfromoptions = NULL;
3398   prob->ops->setup          = NULL;
3399   prob->ops->view           = NULL;
3400   prob->ops->destroy        = PetscDSDestroy_Basic;
3401   PetscFunctionReturn(0);
3402 }
3403 
3404 /*MC
3405   PETSCDSBASIC = "basic" - A discrete system with pointwise residual and boundary residual functions
3406 
3407   Level: intermediate
3408 
3409 .seealso: PetscDSType, PetscDSCreate(), PetscDSSetType()
3410 M*/
3411 
3412 PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS prob)
3413 {
3414   PetscDS_Basic *b;
3415   PetscErrorCode      ierr;
3416 
3417   PetscFunctionBegin;
3418   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
3419   ierr       = PetscNewLog(prob, &b);CHKERRQ(ierr);
3420   prob->data = b;
3421 
3422   ierr = PetscDSInitialize_Basic(prob);CHKERRQ(ierr);
3423   PetscFunctionReturn(0);
3424 }
3425