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