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