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