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