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