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