xref: /petsc/src/dm/dt/interface/dtds.c (revision a04797880822a4ab2b2131e566b75dfe123750f6)
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 /*@C
9   PetscDSRegister - Adds a new PetscDS implementation
10 
11   Not Collective
12 
13   Input Parameters:
14 + name        - The name of a new user-defined creation routine
15 - create_func - The creation routine itself
16 
17   Notes:
18   PetscDSRegister() may be called multiple times to add several user-defined PetscDSs
19 
20   Sample usage:
21 .vb
22     PetscDSRegister("my_ds", MyPetscDSCreate);
23 .ve
24 
25   Then, your PetscDS type can be chosen with the procedural interface via
26 .vb
27     PetscDSCreate(MPI_Comm, PetscDS *);
28     PetscDSSetType(PetscDS, "my_ds");
29 .ve
30    or at runtime via the option
31 .vb
32     -petscds_type my_ds
33 .ve
34 
35   Level: advanced
36 
37 .keywords: PetscDS, register
38 .seealso: PetscDSRegisterAll(), PetscDSRegisterDestroy()
39 
40 @*/
41 PetscErrorCode PetscDSRegister(const char sname[], PetscErrorCode (*function)(PetscDS))
42 {
43   PetscErrorCode ierr;
44 
45   PetscFunctionBegin;
46   ierr = PetscFunctionListAdd(&PetscDSList, sname, function);CHKERRQ(ierr);
47   PetscFunctionReturn(0);
48 }
49 
50 /*@C
51   PetscDSSetType - Builds a particular PetscDS
52 
53   Collective on PetscDS
54 
55   Input Parameters:
56 + prob - The PetscDS object
57 - name - The kind of system
58 
59   Options Database Key:
60 . -petscds_type <type> - Sets the PetscDS type; use -help for a list of available types
61 
62   Level: intermediate
63 
64 .keywords: PetscDS, set, type
65 .seealso: PetscDSGetType(), PetscDSCreate()
66 @*/
67 PetscErrorCode PetscDSSetType(PetscDS prob, PetscDSType name)
68 {
69   PetscErrorCode (*r)(PetscDS);
70   PetscBool      match;
71   PetscErrorCode ierr;
72 
73   PetscFunctionBegin;
74   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
75   ierr = PetscObjectTypeCompare((PetscObject) prob, name, &match);CHKERRQ(ierr);
76   if (match) PetscFunctionReturn(0);
77 
78   ierr = PetscDSRegisterAll();CHKERRQ(ierr);
79   ierr = PetscFunctionListFind(PetscDSList, name, &r);CHKERRQ(ierr);
80   if (!r) SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDS type: %s", name);
81 
82   if (prob->ops->destroy) {
83     ierr             = (*prob->ops->destroy)(prob);CHKERRQ(ierr);
84     prob->ops->destroy = NULL;
85   }
86   ierr = (*r)(prob);CHKERRQ(ierr);
87   ierr = PetscObjectChangeTypeName((PetscObject) prob, name);CHKERRQ(ierr);
88   PetscFunctionReturn(0);
89 }
90 
91 /*@C
92   PetscDSGetType - Gets the PetscDS type name (as a string) from the object.
93 
94   Not Collective
95 
96   Input Parameter:
97 . prob  - The PetscDS
98 
99   Output Parameter:
100 . name - The PetscDS type name
101 
102   Level: intermediate
103 
104 .keywords: PetscDS, get, type, name
105 .seealso: PetscDSSetType(), PetscDSCreate()
106 @*/
107 PetscErrorCode PetscDSGetType(PetscDS prob, PetscDSType *name)
108 {
109   PetscErrorCode ierr;
110 
111   PetscFunctionBegin;
112   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
113   PetscValidPointer(name, 2);
114   ierr = PetscDSRegisterAll();CHKERRQ(ierr);
115   *name = ((PetscObject) prob)->type_name;
116   PetscFunctionReturn(0);
117 }
118 
119 static PetscErrorCode PetscDSView_Ascii(PetscDS prob, PetscViewer viewer)
120 {
121   PetscViewerFormat format;
122   PetscInt          f;
123   PetscErrorCode    ierr;
124 
125   PetscFunctionBegin;
126   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
127   ierr = PetscViewerASCIIPrintf(viewer, "Discrete System with %d fields\n", prob->Nf);CHKERRQ(ierr);
128   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
129   for (f = 0; f < prob->Nf; ++f) {
130     PetscObject  obj;
131     PetscClassId id;
132     const char  *name;
133     PetscInt     Nc;
134 
135     ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
136     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
137     ierr = PetscObjectGetName(obj, &name);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Field %s", name ? name : "<unknown>");CHKERRQ(ierr);
139     if (id == PETSCFE_CLASSID)      {
140       ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);
141       ierr = PetscViewerASCIIPrintf(viewer, " FEM");CHKERRQ(ierr);
142     } else if (id == PETSCFV_CLASSID) {
143       ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);
144       ierr = PetscViewerASCIIPrintf(viewer, " FVM");CHKERRQ(ierr);
145     }
146     else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
147     if (Nc > 1) {ierr = PetscViewerASCIIPrintf(viewer, "%d components", Nc);CHKERRQ(ierr);}
148     else        {ierr = PetscViewerASCIIPrintf(viewer, "%d component ", Nc);CHKERRQ(ierr);}
149     if (prob->implicit[f]) {ierr = PetscViewerASCIIPrintf(viewer, " (implicit)");CHKERRQ(ierr);}
150     else                   {ierr = PetscViewerASCIIPrintf(viewer, " (explicit)");CHKERRQ(ierr);}
151     if (prob->adjacency[f*2+0]) {
152       if (prob->adjacency[f*2+1]) {ierr = PetscViewerASCIIPrintf(viewer, " (adj FVM++)");CHKERRQ(ierr);}
153       else                        {ierr = PetscViewerASCIIPrintf(viewer, " (adj FVM)");CHKERRQ(ierr);}
154     } else {
155       if (prob->adjacency[f*2+1]) {ierr = PetscViewerASCIIPrintf(viewer, " (adj FEM)");CHKERRQ(ierr);}
156       else                        {ierr = PetscViewerASCIIPrintf(viewer, " (adj FUNKY)");CHKERRQ(ierr);}
157     }
158     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
159     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
160       if (id == PETSCFE_CLASSID)      {ierr = PetscFEView((PetscFE) obj, viewer);CHKERRQ(ierr);}
161       else if (id == PETSCFV_CLASSID) {ierr = PetscFVView((PetscFV) obj, viewer);CHKERRQ(ierr);}
162     }
163   }
164   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
165   PetscFunctionReturn(0);
166 }
167 
168 /*@C
169   PetscDSView - Views a PetscDS
170 
171   Collective on PetscDS
172 
173   Input Parameter:
174 + prob - the PetscDS object to view
175 - v  - the viewer
176 
177   Level: developer
178 
179 .seealso PetscDSDestroy()
180 @*/
181 PetscErrorCode PetscDSView(PetscDS prob, PetscViewer v)
182 {
183   PetscBool      iascii;
184   PetscErrorCode ierr;
185 
186   PetscFunctionBegin;
187   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
188   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) prob), &v);CHKERRQ(ierr);}
189   else    {PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);}
190   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
191   if (iascii) {ierr = PetscDSView_Ascii(prob, v);CHKERRQ(ierr);}
192   if (prob->ops->view) {ierr = (*prob->ops->view)(prob, v);CHKERRQ(ierr);}
193   PetscFunctionReturn(0);
194 }
195 
196 /*@
197   PetscDSSetFromOptions - sets parameters in a PetscDS from the options database
198 
199   Collective on PetscDS
200 
201   Input Parameter:
202 . prob - the PetscDS object to set options for
203 
204   Options Database:
205 
206   Level: developer
207 
208 .seealso PetscDSView()
209 @*/
210 PetscErrorCode PetscDSSetFromOptions(PetscDS prob)
211 {
212   DSBoundary     b;
213   const char    *defaultType;
214   char           name[256];
215   PetscBool      flg;
216   PetscErrorCode ierr;
217 
218   PetscFunctionBegin;
219   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
220   if (!((PetscObject) prob)->type_name) {
221     defaultType = PETSCDSBASIC;
222   } else {
223     defaultType = ((PetscObject) prob)->type_name;
224   }
225   ierr = PetscDSRegisterAll();CHKERRQ(ierr);
226 
227   ierr = PetscObjectOptionsBegin((PetscObject) prob);CHKERRQ(ierr);
228   for (b = prob->boundary; b; b = b->next) {
229     char       optname[1024];
230     PetscInt   ids[1024], len = 1024;
231     PetscBool  flg;
232 
233     ierr = PetscSNPrintf(optname, sizeof(optname), "-bc_%s", b->name);CHKERRQ(ierr);
234     ierr = PetscMemzero(ids, sizeof(ids));CHKERRQ(ierr);
235     ierr = PetscOptionsIntArray(optname, "List of boundary IDs", "", ids, &len, &flg);CHKERRQ(ierr);
236     if (flg) {
237       b->numids = len;
238       ierr = PetscFree(b->ids);CHKERRQ(ierr);
239       ierr = PetscMalloc1(len, &b->ids);CHKERRQ(ierr);
240       ierr = PetscMemcpy(b->ids, ids, len*sizeof(PetscInt));CHKERRQ(ierr);
241     }
242     len = 1024;
243     ierr = PetscSNPrintf(optname, sizeof(optname), "-bc_%s_comp", b->name);CHKERRQ(ierr);
244     ierr = PetscMemzero(ids, sizeof(ids));CHKERRQ(ierr);
245     ierr = PetscOptionsIntArray(optname, "List of boundary field components", "", ids, &len, &flg);CHKERRQ(ierr);
246     if (flg) {
247       b->numcomps = len;
248       ierr = PetscFree(b->comps);CHKERRQ(ierr);
249       ierr = PetscMalloc1(len, &b->comps);CHKERRQ(ierr);
250       ierr = PetscMemcpy(b->comps, ids, len*sizeof(PetscInt));CHKERRQ(ierr);
251     }
252   }
253   ierr = PetscOptionsFList("-petscds_type", "Discrete System", "PetscDSSetType", PetscDSList, defaultType, name, 256, &flg);CHKERRQ(ierr);
254   if (flg) {
255     ierr = PetscDSSetType(prob, name);CHKERRQ(ierr);
256   } else if (!((PetscObject) prob)->type_name) {
257     ierr = PetscDSSetType(prob, defaultType);CHKERRQ(ierr);
258   }
259   if (prob->ops->setfromoptions) {ierr = (*prob->ops->setfromoptions)(prob);CHKERRQ(ierr);}
260   /* process any options handlers added with PetscObjectAddOptionsHandler() */
261   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) prob);CHKERRQ(ierr);
262   ierr = PetscOptionsEnd();CHKERRQ(ierr);
263   ierr = PetscDSViewFromOptions(prob, NULL, "-petscds_view");CHKERRQ(ierr);
264   PetscFunctionReturn(0);
265 }
266 
267 /*@C
268   PetscDSSetUp - Construct data structures for the PetscDS
269 
270   Collective on PetscDS
271 
272   Input Parameter:
273 . prob - the PetscDS object to setup
274 
275   Level: developer
276 
277 .seealso PetscDSView(), PetscDSDestroy()
278 @*/
279 PetscErrorCode PetscDSSetUp(PetscDS prob)
280 {
281   const PetscInt Nf = prob->Nf;
282   PetscInt       dim, work, NcMax = 0, NqMax = 0, f;
283   PetscErrorCode ierr;
284 
285   PetscFunctionBegin;
286   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
287   if (prob->setup) PetscFunctionReturn(0);
288   /* Calculate sizes */
289   ierr = PetscDSGetSpatialDimension(prob, &dim);CHKERRQ(ierr);
290   prob->totDim = prob->totComp = 0;
291   ierr = PetscMalloc2(Nf,&prob->Nc,Nf,&prob->Nb);CHKERRQ(ierr);
292   ierr = PetscCalloc2(Nf+1,&prob->off,Nf+1,&prob->offDer);CHKERRQ(ierr);
293   ierr = PetscMalloc4(Nf,&prob->basis,Nf,&prob->basisDer,Nf,&prob->basisFace,Nf,&prob->basisDerFace);CHKERRQ(ierr);
294   for (f = 0; f < Nf; ++f) {
295     PetscObject     obj;
296     PetscClassId    id;
297     PetscQuadrature q;
298     PetscInt        Nq = 0, Nb, Nc;
299 
300     ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr);
301     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
302     if (id == PETSCFE_CLASSID)      {
303       PetscFE fe = (PetscFE) obj;
304 
305       ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr);
306       ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr);
307       ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
308       ierr = PetscFEGetDefaultTabulation(fe, &prob->basis[f], &prob->basisDer[f], NULL);CHKERRQ(ierr);
309       ierr = PetscFEGetFaceTabulation(fe, &prob->basisFace[f], &prob->basisDerFace[f], NULL);CHKERRQ(ierr);
310     } else if (id == PETSCFV_CLASSID) {
311       PetscFV fv = (PetscFV) obj;
312 
313       ierr = PetscFVGetQuadrature(fv, &q);CHKERRQ(ierr);
314       ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr);
315       Nb   = Nc;
316       ierr = PetscFVGetDefaultTabulation(fv, &prob->basis[f], &prob->basisDer[f], NULL);CHKERRQ(ierr);
317       /* TODO: should PetscFV also have face tabulation? Otherwise there will be a null pointer in prob->basisFace */
318     } else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f);
319     prob->Nc[f]       = Nc;
320     prob->Nb[f]       = Nb;
321     prob->off[f+1]    = Nc     + prob->off[f];
322     prob->offDer[f+1] = Nc*dim + prob->offDer[f];
323     if (q) {ierr = PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr);}
324     NqMax          = PetscMax(NqMax, Nq);
325     NcMax          = PetscMax(NcMax, Nc);
326     prob->totDim  += Nb;
327     prob->totComp += Nc;
328   }
329   work = PetscMax(prob->totComp*dim, PetscSqr(NcMax*dim));
330   /* Allocate works space */
331   ierr = PetscMalloc5(prob->totComp,&prob->u,prob->totComp,&prob->u_t,prob->totComp*dim,&prob->u_x,dim,&prob->x,work,&prob->refSpaceDer);CHKERRQ(ierr);
332   ierr = PetscMalloc6(NqMax*NcMax,&prob->f0,NqMax*NcMax*dim,&prob->f1,NqMax*NcMax*NcMax,&prob->g0,NqMax*NcMax*NcMax*dim,&prob->g1,NqMax*NcMax*NcMax*dim,&prob->g2,NqMax*NcMax*NcMax*dim*dim,&prob->g3);CHKERRQ(ierr);
333   if (prob->ops->setup) {ierr = (*prob->ops->setup)(prob);CHKERRQ(ierr);}
334   prob->setup = PETSC_TRUE;
335   PetscFunctionReturn(0);
336 }
337 
338 static PetscErrorCode PetscDSDestroyStructs_Static(PetscDS prob)
339 {
340   PetscErrorCode ierr;
341 
342   PetscFunctionBegin;
343   ierr = PetscFree2(prob->Nc,prob->Nb);CHKERRQ(ierr);
344   ierr = PetscFree2(prob->off,prob->offDer);CHKERRQ(ierr);
345   ierr = PetscFree4(prob->basis,prob->basisDer,prob->basisFace,prob->basisDerFace);CHKERRQ(ierr);
346   ierr = PetscFree5(prob->u,prob->u_t,prob->u_x,prob->x,prob->refSpaceDer);CHKERRQ(ierr);
347   ierr = PetscFree6(prob->f0,prob->f1,prob->g0,prob->g1,prob->g2,prob->g3);CHKERRQ(ierr);
348   PetscFunctionReturn(0);
349 }
350 
351 static PetscErrorCode PetscDSEnlarge_Static(PetscDS prob, PetscInt NfNew)
352 {
353   PetscObject      *tmpd;
354   PetscBool        *tmpi, *tmpa;
355   PetscPointFunc   *tmpobj, *tmpf, *tmpup;
356   PetscPointJac    *tmpg, *tmpgp, *tmpgt;
357   PetscBdPointFunc *tmpfbd;
358   PetscBdPointJac  *tmpgbd;
359   PetscRiemannFunc *tmpr;
360   void            **tmpctx;
361   PetscInt          Nf = prob->Nf, f, i;
362   PetscErrorCode    ierr;
363 
364   PetscFunctionBegin;
365   if (Nf >= NfNew) PetscFunctionReturn(0);
366   prob->setup = PETSC_FALSE;
367   ierr = PetscDSDestroyStructs_Static(prob);CHKERRQ(ierr);
368   ierr = PetscMalloc3(NfNew, &tmpd, NfNew, &tmpi, NfNew*2, &tmpa);CHKERRQ(ierr);
369   for (f = 0; f < Nf; ++f) {tmpd[f] = prob->disc[f]; tmpi[f] = prob->implicit[f]; for (i = 0; i < 2; ++i) tmpa[f*2+i] = prob->adjacency[f*2+i];}
370   for (f = Nf; f < NfNew; ++f) {tmpd[f] = NULL; tmpi[f] = PETSC_TRUE; tmpa[f*2+0] = PETSC_FALSE; tmpa[f*2+1] = PETSC_TRUE;}
371   ierr = PetscFree3(prob->disc, prob->implicit, prob->adjacency);CHKERRQ(ierr);
372   prob->Nf        = NfNew;
373   prob->disc      = tmpd;
374   prob->implicit  = tmpi;
375   prob->adjacency = tmpa;
376   ierr = PetscCalloc7(NfNew, &tmpobj, NfNew*2, &tmpf, NfNew*NfNew*4, &tmpg, NfNew*NfNew*4, &tmpgp, NfNew*NfNew*4, &tmpgt, NfNew, &tmpr, NfNew, &tmpctx);CHKERRQ(ierr);
377   ierr = PetscCalloc1(NfNew, &tmpup);CHKERRQ(ierr);
378   for (f = 0; f < Nf; ++f) tmpobj[f] = prob->obj[f];
379   for (f = 0; f < Nf*2; ++f) tmpf[f] = prob->f[f];
380   for (f = 0; f < Nf*Nf*4; ++f) tmpg[f] = prob->g[f];
381   for (f = 0; f < Nf*Nf*4; ++f) tmpgp[f] = prob->gp[f];
382   for (f = 0; f < Nf; ++f) tmpr[f] = prob->r[f];
383   for (f = 0; f < Nf; ++f) tmpup[f] = prob->update[f];
384   for (f = 0; f < Nf; ++f) tmpctx[f] = prob->ctx[f];
385   for (f = Nf; f < NfNew; ++f) tmpobj[f] = NULL;
386   for (f = Nf*2; f < NfNew*2; ++f) tmpf[f] = NULL;
387   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpg[f] = NULL;
388   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpgp[f] = NULL;
389   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpgt[f] = NULL;
390   for (f = Nf; f < NfNew; ++f) tmpr[f] = NULL;
391   for (f = Nf; f < NfNew; ++f) tmpup[f] = NULL;
392   for (f = Nf; f < NfNew; ++f) tmpctx[f] = NULL;
393   ierr = PetscFree7(prob->obj, prob->f, prob->g, prob->gp, prob->gt, prob->r, prob->ctx);CHKERRQ(ierr);
394   ierr = PetscFree(prob->update);CHKERRQ(ierr);
395   prob->obj = tmpobj;
396   prob->f   = tmpf;
397   prob->g   = tmpg;
398   prob->gp  = tmpgp;
399   prob->gt  = tmpgt;
400   prob->r   = tmpr;
401   prob->update = tmpup;
402   prob->ctx = tmpctx;
403   ierr = PetscCalloc2(NfNew*2, &tmpfbd, NfNew*NfNew*4, &tmpgbd);CHKERRQ(ierr);
404   for (f = 0; f < Nf*2; ++f) tmpfbd[f] = prob->fBd[f];
405   for (f = 0; f < Nf*Nf*4; ++f) tmpgbd[f] = prob->gBd[f];
406   for (f = Nf*2; f < NfNew*2; ++f) tmpfbd[f] = NULL;
407   for (f = Nf*Nf*4; f < NfNew*NfNew*4; ++f) tmpgbd[f] = NULL;
408   ierr = PetscFree2(prob->fBd, prob->gBd);CHKERRQ(ierr);
409   prob->fBd = tmpfbd;
410   prob->gBd = tmpgbd;
411   PetscFunctionReturn(0);
412 }
413 
414 /*@
415   PetscDSDestroy - Destroys a PetscDS object
416 
417   Collective on PetscDS
418 
419   Input Parameter:
420 . prob - the PetscDS object to destroy
421 
422   Level: developer
423 
424 .seealso PetscDSView()
425 @*/
426 PetscErrorCode PetscDSDestroy(PetscDS *prob)
427 {
428   PetscInt       f;
429   DSBoundary     next;
430   PetscErrorCode ierr;
431 
432   PetscFunctionBegin;
433   if (!*prob) PetscFunctionReturn(0);
434   PetscValidHeaderSpecific((*prob), PETSCDS_CLASSID, 1);
435 
436   if (--((PetscObject)(*prob))->refct > 0) {*prob = 0; PetscFunctionReturn(0);}
437   ((PetscObject) (*prob))->refct = 0;
438   ierr = PetscDSDestroyStructs_Static(*prob);CHKERRQ(ierr);
439   for (f = 0; f < (*prob)->Nf; ++f) {
440     ierr = PetscObjectDereference((*prob)->disc[f]);CHKERRQ(ierr);
441   }
442   ierr = PetscFree3((*prob)->disc, (*prob)->implicit, (*prob)->adjacency);CHKERRQ(ierr);
443   ierr = PetscFree7((*prob)->obj,(*prob)->f,(*prob)->g,(*prob)->gp,(*prob)->gt,(*prob)->r,(*prob)->ctx);CHKERRQ(ierr);
444   ierr = PetscFree((*prob)->update);CHKERRQ(ierr);
445   ierr = PetscFree2((*prob)->fBd,(*prob)->gBd);CHKERRQ(ierr);
446   if ((*prob)->ops->destroy) {ierr = (*(*prob)->ops->destroy)(*prob);CHKERRQ(ierr);}
447   next = (*prob)->boundary;
448   while (next) {
449     DSBoundary b = next;
450 
451     next = b->next;
452     ierr = PetscFree(b->comps);CHKERRQ(ierr);
453     ierr = PetscFree(b->ids);CHKERRQ(ierr);
454     ierr = PetscFree(b->name);CHKERRQ(ierr);
455     ierr = PetscFree(b->labelname);CHKERRQ(ierr);
456     ierr = PetscFree(b);CHKERRQ(ierr);
457   }
458   ierr = PetscHeaderDestroy(prob);CHKERRQ(ierr);
459   PetscFunctionReturn(0);
460 }
461 
462 /*@
463   PetscDSCreate - Creates an empty PetscDS object. The type can then be set with PetscDSSetType().
464 
465   Collective on MPI_Comm
466 
467   Input Parameter:
468 . comm - The communicator for the PetscDS object
469 
470   Output Parameter:
471 . prob - The PetscDS object
472 
473   Level: beginner
474 
475 .seealso: PetscDSSetType(), PETSCDSBASIC
476 @*/
477 PetscErrorCode PetscDSCreate(MPI_Comm comm, PetscDS *prob)
478 {
479   PetscDS   p;
480   PetscErrorCode ierr;
481 
482   PetscFunctionBegin;
483   PetscValidPointer(prob, 2);
484   *prob  = NULL;
485   ierr = PetscDSInitializePackage();CHKERRQ(ierr);
486 
487   ierr = PetscHeaderCreate(p, PETSCDS_CLASSID, "PetscDS", "Discrete System", "PetscDS", comm, PetscDSDestroy, PetscDSView);CHKERRQ(ierr);
488 
489   p->Nf    = 0;
490   p->setup = PETSC_FALSE;
491 
492   *prob = p;
493   PetscFunctionReturn(0);
494 }
495 
496 /*@
497   PetscDSGetNumFields - Returns the number of fields in the DS
498 
499   Not collective
500 
501   Input Parameter:
502 . prob - The PetscDS object
503 
504   Output Parameter:
505 . Nf - The number of fields
506 
507   Level: beginner
508 
509 .seealso: PetscDSGetSpatialDimension(), PetscDSCreate()
510 @*/
511 PetscErrorCode PetscDSGetNumFields(PetscDS prob, PetscInt *Nf)
512 {
513   PetscFunctionBegin;
514   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
515   PetscValidPointer(Nf, 2);
516   *Nf = prob->Nf;
517   PetscFunctionReturn(0);
518 }
519 
520 /*@
521   PetscDSGetSpatialDimension - Returns the spatial dimension of the DS
522 
523   Not collective
524 
525   Input Parameter:
526 . prob - The PetscDS object
527 
528   Output Parameter:
529 . dim - The spatial dimension
530 
531   Level: beginner
532 
533 .seealso: PetscDSGetNumFields(), PetscDSCreate()
534 @*/
535 PetscErrorCode PetscDSGetSpatialDimension(PetscDS prob, PetscInt *dim)
536 {
537   PetscErrorCode ierr;
538 
539   PetscFunctionBegin;
540   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
541   PetscValidPointer(dim, 2);
542   *dim = 0;
543   if (prob->Nf) {
544     PetscObject  obj;
545     PetscClassId id;
546 
547     ierr = PetscDSGetDiscretization(prob, 0, &obj);CHKERRQ(ierr);
548     ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
549     if (id == PETSCFE_CLASSID)      {ierr = PetscFEGetSpatialDimension((PetscFE) obj, dim);CHKERRQ(ierr);}
550     else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetSpatialDimension((PetscFV) obj, dim);CHKERRQ(ierr);}
551     else SETERRQ1(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", 0);
552   }
553   PetscFunctionReturn(0);
554 }
555 
556 /*@
557   PetscDSGetTotalDimension - Returns the total size of the approximation space for this system
558 
559   Not collective
560 
561   Input Parameter:
562 . prob - The PetscDS object
563 
564   Output Parameter:
565 . dim - The total problem dimension
566 
567   Level: beginner
568 
569 .seealso: PetscDSGetNumFields(), PetscDSCreate()
570 @*/
571 PetscErrorCode PetscDSGetTotalDimension(PetscDS prob, PetscInt *dim)
572 {
573   PetscErrorCode ierr;
574 
575   PetscFunctionBegin;
576   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
577   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
578   PetscValidPointer(dim, 2);
579   *dim = prob->totDim;
580   PetscFunctionReturn(0);
581 }
582 
583 /*@
584   PetscDSGetTotalComponents - Returns the total number of components in this system
585 
586   Not collective
587 
588   Input Parameter:
589 . prob - The PetscDS object
590 
591   Output Parameter:
592 . dim - The total number of components
593 
594   Level: beginner
595 
596 .seealso: PetscDSGetNumFields(), PetscDSCreate()
597 @*/
598 PetscErrorCode PetscDSGetTotalComponents(PetscDS prob, PetscInt *Nc)
599 {
600   PetscErrorCode ierr;
601 
602   PetscFunctionBegin;
603   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
604   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
605   PetscValidPointer(Nc, 2);
606   *Nc = prob->totComp;
607   PetscFunctionReturn(0);
608 }
609 
610 /*@
611   PetscDSGetDiscretization - Returns the discretization object for the given field
612 
613   Not collective
614 
615   Input Parameters:
616 + prob - The PetscDS object
617 - f - The field number
618 
619   Output Parameter:
620 . disc - The discretization object
621 
622   Level: beginner
623 
624 .seealso: PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
625 @*/
626 PetscErrorCode PetscDSGetDiscretization(PetscDS prob, PetscInt f, PetscObject *disc)
627 {
628   PetscFunctionBegin;
629   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
630   PetscValidPointer(disc, 3);
631   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);
632   *disc = prob->disc[f];
633   PetscFunctionReturn(0);
634 }
635 
636 /*@
637   PetscDSSetDiscretization - Sets the discretization object for the given field
638 
639   Not collective
640 
641   Input Parameters:
642 + prob - The PetscDS object
643 . f - The field number
644 - disc - The discretization object
645 
646   Level: beginner
647 
648 .seealso: PetscDSGetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
649 @*/
650 PetscErrorCode PetscDSSetDiscretization(PetscDS prob, PetscInt f, PetscObject disc)
651 {
652   PetscErrorCode ierr;
653 
654   PetscFunctionBegin;
655   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
656   PetscValidPointer(disc, 3);
657   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
658   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
659   if (prob->disc[f]) {ierr = PetscObjectDereference(prob->disc[f]);CHKERRQ(ierr);}
660   prob->disc[f] = disc;
661   ierr = PetscObjectReference(disc);CHKERRQ(ierr);
662   {
663     PetscClassId id;
664 
665     ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
666     if (id == PETSCFV_CLASSID) {
667       prob->implicit[f]      = PETSC_FALSE;
668       prob->adjacency[f*2+0] = PETSC_TRUE;
669       prob->adjacency[f*2+1] = PETSC_FALSE;
670     }
671   }
672   PetscFunctionReturn(0);
673 }
674 
675 /*@
676   PetscDSAddDiscretization - Adds a discretization object
677 
678   Not collective
679 
680   Input Parameters:
681 + prob - The PetscDS object
682 - disc - The boundary discretization object
683 
684   Level: beginner
685 
686 .seealso: PetscDSGetDiscretization(), PetscDSSetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
687 @*/
688 PetscErrorCode PetscDSAddDiscretization(PetscDS prob, PetscObject disc)
689 {
690   PetscErrorCode ierr;
691 
692   PetscFunctionBegin;
693   ierr = PetscDSSetDiscretization(prob, prob->Nf, disc);CHKERRQ(ierr);
694   PetscFunctionReturn(0);
695 }
696 
697 /*@
698   PetscDSGetImplicit - Returns the flag for implicit solve for this field. This is just a guide for IMEX
699 
700   Not collective
701 
702   Input Parameters:
703 + prob - The PetscDS object
704 - f - The field number
705 
706   Output Parameter:
707 . implicit - The flag indicating what kind of solve to use for this field
708 
709   Level: developer
710 
711 .seealso: PetscDSSetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
712 @*/
713 PetscErrorCode PetscDSGetImplicit(PetscDS prob, PetscInt f, PetscBool *implicit)
714 {
715   PetscFunctionBegin;
716   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
717   PetscValidPointer(implicit, 3);
718   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);
719   *implicit = prob->implicit[f];
720   PetscFunctionReturn(0);
721 }
722 
723 /*@
724   PetscDSSetImplicit - Set the flag for implicit solve for this field. This is just a guide for IMEX
725 
726   Not collective
727 
728   Input Parameters:
729 + prob - The PetscDS object
730 . f - The field number
731 - implicit - The flag indicating what kind of solve to use for this field
732 
733   Level: developer
734 
735 .seealso: PetscDSGetImplicit(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
736 @*/
737 PetscErrorCode PetscDSSetImplicit(PetscDS prob, PetscInt f, PetscBool implicit)
738 {
739   PetscFunctionBegin;
740   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
741   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);
742   prob->implicit[f] = implicit;
743   PetscFunctionReturn(0);
744 }
745 
746 /*@
747   PetscDSGetAdjacency - Returns the flags for determining variable influence
748 
749   Not collective
750 
751   Input Parameters:
752 + prob - The PetscDS object
753 - f - The field number
754 
755   Output Parameter:
756 + useCone    - Flag for variable influence starting with the cone operation
757 - useClosure - Flag for variable influence using transitive closure
758 
759   Note: See the discussion in DMPlexGetAdjacencyUseCone() and DMPlexGetAdjacencyUseClosure()
760 
761   Level: developer
762 
763 .seealso: PetscDSSetAdjacency(), DMPlexGetAdjacencyUseCone(), DMPlexGetAdjacencyUseClosure(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
764 @*/
765 PetscErrorCode PetscDSGetAdjacency(PetscDS prob, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
766 {
767   PetscFunctionBegin;
768   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
769   PetscValidPointer(useCone, 3);
770   PetscValidPointer(useClosure, 4);
771   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);
772   *useCone    = prob->adjacency[f*2+0];
773   *useClosure = prob->adjacency[f*2+1];
774   PetscFunctionReturn(0);
775 }
776 
777 /*@
778   PetscDSSetAdjacency - Set the flags for determining variable influence
779 
780   Not collective
781 
782   Input Parameters:
783 + prob - The PetscDS object
784 . f - The field number
785 . useCone    - Flag for variable influence starting with the cone operation
786 - useClosure - Flag for variable influence using transitive closure
787 
788   Note: See the discussion in DMPlexGetAdjacencyUseCone() and DMPlexGetAdjacencyUseClosure()
789 
790   Level: developer
791 
792 .seealso: PetscDSGetAdjacency(), DMPlexGetAdjacencyUseCone(), DMPlexGetAdjacencyUseClosure(), PetscDSSetDiscretization(), PetscDSAddDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
793 @*/
794 PetscErrorCode PetscDSSetAdjacency(PetscDS prob, PetscInt f, PetscBool useCone, PetscBool useClosure)
795 {
796   PetscFunctionBegin;
797   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
798   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);
799   prob->adjacency[f*2+0] = useCone;
800   prob->adjacency[f*2+1] = useClosure;
801   PetscFunctionReturn(0);
802 }
803 
804 PetscErrorCode PetscDSGetObjective(PetscDS prob, PetscInt f,
805                                    void (**obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
806                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
807                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
808                                                 PetscReal t, const PetscReal x[], PetscScalar obj[]))
809 {
810   PetscFunctionBegin;
811   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
812   PetscValidPointer(obj, 2);
813   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);
814   *obj = prob->obj[f];
815   PetscFunctionReturn(0);
816 }
817 
818 PetscErrorCode PetscDSSetObjective(PetscDS prob, PetscInt f,
819                                    void (*obj)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
820                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
821                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
822                                                PetscReal t, const PetscReal x[], PetscScalar obj[]))
823 {
824   PetscErrorCode ierr;
825 
826   PetscFunctionBegin;
827   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
828   if (obj) PetscValidFunction(obj, 2);
829   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
830   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
831   prob->obj[f] = obj;
832   PetscFunctionReturn(0);
833 }
834 
835 /*@C
836   PetscDSGetResidual - Get the pointwise residual function for a given test field
837 
838   Not collective
839 
840   Input Parameters:
841 + prob - The PetscDS
842 - f    - The test field number
843 
844   Output Parameters:
845 + f0 - integrand for the test function term
846 - f1 - integrand for the test function gradient term
847 
848   Note: We are using a first order FEM model for the weak form:
849 
850   \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)
851 
852 The calling sequence for the callbacks f0 and f1 is given by:
853 
854 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
855 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
856 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
857 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
858 
859 + dim - the spatial dimension
860 . Nf - the number of fields
861 . uOff - the offset into u[] and u_t[] for each field
862 . uOff_x - the offset into u_x[] for each field
863 . u - each field evaluated at the current point
864 . u_t - the time derivative of each field evaluated at the current point
865 . u_x - the gradient of each field evaluated at the current point
866 . aOff - the offset into a[] and a_t[] for each auxiliary field
867 . aOff_x - the offset into a_x[] for each auxiliary field
868 . a - each auxiliary field evaluated at the current point
869 . a_t - the time derivative of each auxiliary field evaluated at the current point
870 . a_x - the gradient of auxiliary each field evaluated at the current point
871 . t - current time
872 . x - coordinates of the current point
873 - f0 - output values at the current point
874 
875   Level: intermediate
876 
877 .seealso: PetscDSSetResidual()
878 @*/
879 PetscErrorCode PetscDSGetResidual(PetscDS prob, PetscInt f,
880                                   void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
881                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
882                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
883                                               PetscReal t, const PetscReal x[], PetscScalar f0[]),
884                                   void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
885                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
886                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
887                                               PetscReal t, const PetscReal x[], PetscScalar f1[]))
888 {
889   PetscFunctionBegin;
890   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
891   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);
892   if (f0) {PetscValidPointer(f0, 3); *f0 = prob->f[f*2+0];}
893   if (f1) {PetscValidPointer(f1, 4); *f1 = prob->f[f*2+1];}
894   PetscFunctionReturn(0);
895 }
896 
897 /*@C
898   PetscDSSetResidual - Set the pointwise residual function for a given test field
899 
900   Not collective
901 
902   Input Parameters:
903 + prob - The PetscDS
904 . f    - The test field number
905 . f0 - integrand for the test function term
906 - f1 - integrand for the test function gradient term
907 
908   Note: We are using a first order FEM model for the weak form:
909 
910   \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)
911 
912 The calling sequence for the callbacks f0 and f1 is given by:
913 
914 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
915 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
916 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
917 $    PetscReal t, const PetscReal x[], PetscScalar f0[])
918 
919 + dim - the spatial dimension
920 . Nf - the number of fields
921 . uOff - the offset into u[] and u_t[] for each field
922 . uOff_x - the offset into u_x[] for each field
923 . u - each field evaluated at the current point
924 . u_t - the time derivative of each field evaluated at the current point
925 . u_x - the gradient of each field evaluated at the current point
926 . aOff - the offset into a[] and a_t[] for each auxiliary field
927 . aOff_x - the offset into a_x[] for each auxiliary field
928 . a - each auxiliary field evaluated at the current point
929 . a_t - the time derivative of each auxiliary field evaluated at the current point
930 . a_x - the gradient of auxiliary each field evaluated at the current point
931 . t - current time
932 . x - coordinates of the current point
933 - f0 - output values at the current point
934 
935   Level: intermediate
936 
937 .seealso: PetscDSGetResidual()
938 @*/
939 PetscErrorCode PetscDSSetResidual(PetscDS prob, PetscInt f,
940                                   void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
941                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
942                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
943                                              PetscReal t, const PetscReal x[], PetscScalar f0[]),
944                                   void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
945                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
946                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
947                                              PetscReal t, const PetscReal x[], PetscScalar f1[]))
948 {
949   PetscErrorCode ierr;
950 
951   PetscFunctionBegin;
952   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
953   if (f0) PetscValidFunction(f0, 3);
954   if (f1) PetscValidFunction(f1, 4);
955   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
956   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
957   prob->f[f*2+0] = f0;
958   prob->f[f*2+1] = f1;
959   PetscFunctionReturn(0);
960 }
961 
962 /*@C
963   PetscDSHasJacobian - Signals that Jacobian functions have been set
964 
965   Not collective
966 
967   Input Parameter:
968 . prob - The PetscDS
969 
970   Output Parameter:
971 . hasJac - flag that pointwise function for the Jacobian has been set
972 
973   Level: intermediate
974 
975 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
976 @*/
977 PetscErrorCode PetscDSHasJacobian(PetscDS prob, PetscBool *hasJac)
978 {
979   PetscInt f, g, h;
980 
981   PetscFunctionBegin;
982   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
983   *hasJac = PETSC_FALSE;
984   for (f = 0; f < prob->Nf; ++f) {
985     for (g = 0; g < prob->Nf; ++g) {
986       for (h = 0; h < 4; ++h) {
987         if (prob->g[(f*prob->Nf + g)*4+h]) *hasJac = PETSC_TRUE;
988       }
989     }
990   }
991   PetscFunctionReturn(0);
992 }
993 
994 /*@C
995   PetscDSGetJacobian - Get the pointwise Jacobian function for given test and basis field
996 
997   Not collective
998 
999   Input Parameters:
1000 + prob - The PetscDS
1001 . f    - The test field number
1002 - g    - The field number
1003 
1004   Output Parameters:
1005 + g0 - integrand for the test and basis function term
1006 . g1 - integrand for the test function and basis function gradient term
1007 . g2 - integrand for the test function gradient and basis function term
1008 - g3 - integrand for the test function gradient and basis function gradient term
1009 
1010   Note: We are using a first order FEM model for the weak form:
1011 
1012   \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
1013 
1014 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1015 
1016 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1017 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1018 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1019 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1020 
1021 + dim - the spatial dimension
1022 . Nf - the number of fields
1023 . uOff - the offset into u[] and u_t[] for each field
1024 . uOff_x - the offset into u_x[] for each field
1025 . u - each field evaluated at the current point
1026 . u_t - the time derivative of each field evaluated at the current point
1027 . u_x - the gradient of each field evaluated at the current point
1028 . aOff - the offset into a[] and a_t[] for each auxiliary field
1029 . aOff_x - the offset into a_x[] for each auxiliary field
1030 . a - each auxiliary field evaluated at the current point
1031 . a_t - the time derivative of each auxiliary field evaluated at the current point
1032 . a_x - the gradient of auxiliary each field evaluated at the current point
1033 . t - current time
1034 . u_tShift - the multiplier a for dF/dU_t
1035 . x - coordinates of the current point
1036 - g0 - output values at the current point
1037 
1038   Level: intermediate
1039 
1040 .seealso: PetscDSSetJacobian()
1041 @*/
1042 PetscErrorCode PetscDSGetJacobian(PetscDS prob, PetscInt f, PetscInt g,
1043                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1044                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1045                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1046                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g0[]),
1047                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1048                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1049                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1050                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g1[]),
1051                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1052                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1053                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1054                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g2[]),
1055                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1056                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1057                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1058                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g3[]))
1059 {
1060   PetscFunctionBegin;
1061   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1062   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);
1063   if ((g < 0) || (g >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, prob->Nf);
1064   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->g[(f*prob->Nf + g)*4+0];}
1065   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->g[(f*prob->Nf + g)*4+1];}
1066   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->g[(f*prob->Nf + g)*4+2];}
1067   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->g[(f*prob->Nf + g)*4+3];}
1068   PetscFunctionReturn(0);
1069 }
1070 
1071 /*@C
1072   PetscDSSetJacobian - Set the pointwise Jacobian function for given test and basis fields
1073 
1074   Not collective
1075 
1076   Input Parameters:
1077 + prob - The PetscDS
1078 . f    - The test field number
1079 . g    - The field number
1080 . g0 - integrand for the test and basis function term
1081 . g1 - integrand for the test function and basis function gradient term
1082 . g2 - integrand for the test function gradient and basis function term
1083 - g3 - integrand for the test function gradient and basis function gradient term
1084 
1085   Note: We are using a first order FEM model for the weak form:
1086 
1087   \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
1088 
1089 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1090 
1091 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1092 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1093 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1094 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1095 
1096 + dim - the spatial dimension
1097 . Nf - the number of fields
1098 . uOff - the offset into u[] and u_t[] for each field
1099 . uOff_x - the offset into u_x[] for each field
1100 . u - each field evaluated at the current point
1101 . u_t - the time derivative of each field evaluated at the current point
1102 . u_x - the gradient of each field evaluated at the current point
1103 . aOff - the offset into a[] and a_t[] for each auxiliary field
1104 . aOff_x - the offset into a_x[] for each auxiliary field
1105 . a - each auxiliary field evaluated at the current point
1106 . a_t - the time derivative of each auxiliary field evaluated at the current point
1107 . a_x - the gradient of auxiliary each field evaluated at the current point
1108 . t - current time
1109 . u_tShift - the multiplier a for dF/dU_t
1110 . x - coordinates of the current point
1111 - g0 - output values at the current point
1112 
1113   Level: intermediate
1114 
1115 .seealso: PetscDSGetJacobian()
1116 @*/
1117 PetscErrorCode PetscDSSetJacobian(PetscDS prob, PetscInt f, PetscInt g,
1118                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1119                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1120                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1121                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g0[]),
1122                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1123                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1124                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1125                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g1[]),
1126                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1127                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1128                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1129                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g2[]),
1130                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1131                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1132                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1133                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g3[]))
1134 {
1135   PetscErrorCode ierr;
1136 
1137   PetscFunctionBegin;
1138   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1139   if (g0) PetscValidFunction(g0, 4);
1140   if (g1) PetscValidFunction(g1, 5);
1141   if (g2) PetscValidFunction(g2, 6);
1142   if (g3) PetscValidFunction(g3, 7);
1143   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1144   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1145   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1146   prob->g[(f*prob->Nf + g)*4+0] = g0;
1147   prob->g[(f*prob->Nf + g)*4+1] = g1;
1148   prob->g[(f*prob->Nf + g)*4+2] = g2;
1149   prob->g[(f*prob->Nf + g)*4+3] = g3;
1150   PetscFunctionReturn(0);
1151 }
1152 
1153 /*@C
1154   PetscDSHasJacobianPreconditioner - Signals that a Jacobian preconditioner matrix has been set
1155 
1156   Not collective
1157 
1158   Input Parameter:
1159 . prob - The PetscDS
1160 
1161   Output Parameter:
1162 . hasJacPre - flag that pointwise function for Jacobian preconditioner matrix has been set
1163 
1164   Level: intermediate
1165 
1166 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1167 @*/
1168 PetscErrorCode PetscDSHasJacobianPreconditioner(PetscDS prob, PetscBool *hasJacPre)
1169 {
1170   PetscInt f, g, h;
1171 
1172   PetscFunctionBegin;
1173   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1174   *hasJacPre = PETSC_FALSE;
1175   for (f = 0; f < prob->Nf; ++f) {
1176     for (g = 0; g < prob->Nf; ++g) {
1177       for (h = 0; h < 4; ++h) {
1178         if (prob->gp[(f*prob->Nf + g)*4+h]) *hasJacPre = PETSC_TRUE;
1179       }
1180     }
1181   }
1182   PetscFunctionReturn(0);
1183 }
1184 
1185 /*@C
1186   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.
1187 
1188   Not collective
1189 
1190   Input Parameters:
1191 + prob - The PetscDS
1192 . f    - The test field number
1193 - g    - The field number
1194 
1195   Output Parameters:
1196 + g0 - integrand for the test and basis function term
1197 . g1 - integrand for the test function and basis function gradient term
1198 . g2 - integrand for the test function gradient and basis function term
1199 - g3 - integrand for the test function gradient and basis function gradient term
1200 
1201   Note: We are using a first order FEM model for the weak form:
1202 
1203   \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
1204 
1205 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1206 
1207 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1208 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1209 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1210 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1211 
1212 + dim - the spatial dimension
1213 . Nf - the number of fields
1214 . uOff - the offset into u[] and u_t[] for each field
1215 . uOff_x - the offset into u_x[] for each field
1216 . u - each field evaluated at the current point
1217 . u_t - the time derivative of each field evaluated at the current point
1218 . u_x - the gradient of each field evaluated at the current point
1219 . aOff - the offset into a[] and a_t[] for each auxiliary field
1220 . aOff_x - the offset into a_x[] for each auxiliary field
1221 . a - each auxiliary field evaluated at the current point
1222 . a_t - the time derivative of each auxiliary field evaluated at the current point
1223 . a_x - the gradient of auxiliary each field evaluated at the current point
1224 . t - current time
1225 . u_tShift - the multiplier a for dF/dU_t
1226 . x - coordinates of the current point
1227 - g0 - output values at the current point
1228 
1229   Level: intermediate
1230 
1231 .seealso: PetscDSSetJacobianPreconditioner(), PetscDSGetJacobian()
1232 @*/
1233 PetscErrorCode PetscDSGetJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
1234                                   void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1235                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1236                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1237                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g0[]),
1238                                   void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1239                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1240                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1241                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g1[]),
1242                                   void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1243                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1244                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1245                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g2[]),
1246                                   void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1247                                               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1248                                               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1249                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g3[]))
1250 {
1251   PetscFunctionBegin;
1252   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1253   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);
1254   if ((g < 0) || (g >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, prob->Nf);
1255   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gp[(f*prob->Nf + g)*4+0];}
1256   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gp[(f*prob->Nf + g)*4+1];}
1257   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gp[(f*prob->Nf + g)*4+2];}
1258   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gp[(f*prob->Nf + g)*4+3];}
1259   PetscFunctionReturn(0);
1260 }
1261 
1262 /*@C
1263   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.
1264 
1265   Not collective
1266 
1267   Input Parameters:
1268 + prob - The PetscDS
1269 . f    - The test field number
1270 . g    - The field number
1271 . g0 - integrand for the test and basis function term
1272 . g1 - integrand for the test function and basis function gradient term
1273 . g2 - integrand for the test function gradient and basis function term
1274 - g3 - integrand for the test function gradient and basis function gradient term
1275 
1276   Note: We are using a first order FEM model for the weak form:
1277 
1278   \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
1279 
1280 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1281 
1282 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1283 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1284 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1285 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1286 
1287 + dim - the spatial dimension
1288 . Nf - the number of fields
1289 . uOff - the offset into u[] and u_t[] for each field
1290 . uOff_x - the offset into u_x[] for each field
1291 . u - each field evaluated at the current point
1292 . u_t - the time derivative of each field evaluated at the current point
1293 . u_x - the gradient of each field evaluated at the current point
1294 . aOff - the offset into a[] and a_t[] for each auxiliary field
1295 . aOff_x - the offset into a_x[] for each auxiliary field
1296 . a - each auxiliary field evaluated at the current point
1297 . a_t - the time derivative of each auxiliary field evaluated at the current point
1298 . a_x - the gradient of auxiliary each field evaluated at the current point
1299 . t - current time
1300 . u_tShift - the multiplier a for dF/dU_t
1301 . x - coordinates of the current point
1302 - g0 - output values at the current point
1303 
1304   Level: intermediate
1305 
1306 .seealso: PetscDSGetJacobianPreconditioner(), PetscDSSetJacobian()
1307 @*/
1308 PetscErrorCode PetscDSSetJacobianPreconditioner(PetscDS prob, PetscInt f, PetscInt g,
1309                                   void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1310                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1311                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1312                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g0[]),
1313                                   void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1314                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1315                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1316                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g1[]),
1317                                   void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1318                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1319                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1320                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g2[]),
1321                                   void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1322                                              const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1323                                              const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1324                                              PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g3[]))
1325 {
1326   PetscErrorCode ierr;
1327 
1328   PetscFunctionBegin;
1329   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1330   if (g0) PetscValidFunction(g0, 4);
1331   if (g1) PetscValidFunction(g1, 5);
1332   if (g2) PetscValidFunction(g2, 6);
1333   if (g3) PetscValidFunction(g3, 7);
1334   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1335   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1336   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1337   prob->gp[(f*prob->Nf + g)*4+0] = g0;
1338   prob->gp[(f*prob->Nf + g)*4+1] = g1;
1339   prob->gp[(f*prob->Nf + g)*4+2] = g2;
1340   prob->gp[(f*prob->Nf + g)*4+3] = g3;
1341   PetscFunctionReturn(0);
1342 }
1343 
1344 /*@C
1345   PetscDSHasDynamicJacobian - Signals that a dynamic Jacobian, dF/du_t, has been set
1346 
1347   Not collective
1348 
1349   Input Parameter:
1350 . prob - The PetscDS
1351 
1352   Output Parameter:
1353 . hasDynJac - flag that pointwise function for dynamic Jacobian has been set
1354 
1355   Level: intermediate
1356 
1357 .seealso: PetscDSGetDynamicJacobian(), PetscDSSetDynamicJacobian(), PetscDSGetJacobian()
1358 @*/
1359 PetscErrorCode PetscDSHasDynamicJacobian(PetscDS prob, PetscBool *hasDynJac)
1360 {
1361   PetscInt f, g, h;
1362 
1363   PetscFunctionBegin;
1364   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1365   *hasDynJac = PETSC_FALSE;
1366   for (f = 0; f < prob->Nf; ++f) {
1367     for (g = 0; g < prob->Nf; ++g) {
1368       for (h = 0; h < 4; ++h) {
1369         if (prob->gt[(f*prob->Nf + g)*4+h]) *hasDynJac = PETSC_TRUE;
1370       }
1371     }
1372   }
1373   PetscFunctionReturn(0);
1374 }
1375 
1376 /*@C
1377   PetscDSGetDynamicJacobian - Get the pointwise dynamic Jacobian, dF/du_t, function for given test and basis field
1378 
1379   Not collective
1380 
1381   Input Parameters:
1382 + prob - The PetscDS
1383 . f    - The test field number
1384 - g    - The field number
1385 
1386   Output Parameters:
1387 + g0 - integrand for the test and basis function term
1388 . g1 - integrand for the test function and basis function gradient term
1389 . g2 - integrand for the test function gradient and basis function term
1390 - g3 - integrand for the test function gradient and basis function gradient term
1391 
1392   Note: We are using a first order FEM model for the weak form:
1393 
1394   \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
1395 
1396 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1397 
1398 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1399 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1400 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1401 $    PetscReal t, const PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
1402 
1403 + dim - the spatial dimension
1404 . Nf - the number of fields
1405 . uOff - the offset into u[] and u_t[] for each field
1406 . uOff_x - the offset into u_x[] for each field
1407 . u - each field evaluated at the current point
1408 . u_t - the time derivative of each field evaluated at the current point
1409 . u_x - the gradient of each field evaluated at the current point
1410 . aOff - the offset into a[] and a_t[] for each auxiliary field
1411 . aOff_x - the offset into a_x[] for each auxiliary field
1412 . a - each auxiliary field evaluated at the current point
1413 . a_t - the time derivative of each auxiliary field evaluated at the current point
1414 . a_x - the gradient of auxiliary each field evaluated at the current point
1415 . t - current time
1416 . u_tShift - the multiplier a for dF/dU_t
1417 . x - coordinates of the current point
1418 - g0 - output values at the current point
1419 
1420   Level: intermediate
1421 
1422 .seealso: PetscDSSetJacobian()
1423 @*/
1424 PetscErrorCode PetscDSGetDynamicJacobian(PetscDS prob, PetscInt f, PetscInt g,
1425                                          void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1426                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1427                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1428                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g0[]),
1429                                          void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1430                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1431                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1432                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g1[]),
1433                                          void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1434                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1435                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1436                                               PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g2[]),
1437                                          void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1438                                                      const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1439                                                      const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1440                                                      PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g3[]))
1441 {
1442   PetscFunctionBegin;
1443   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1444   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);
1445   if ((g < 0) || (g >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, prob->Nf);
1446   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gt[(f*prob->Nf + g)*4+0];}
1447   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gt[(f*prob->Nf + g)*4+1];}
1448   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gt[(f*prob->Nf + g)*4+2];}
1449   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gt[(f*prob->Nf + g)*4+3];}
1450   PetscFunctionReturn(0);
1451 }
1452 
1453 /*@C
1454   PetscDSSetDynamicJacobian - Set the pointwise dynamic Jacobian, dF/du_t, function for given test and basis fields
1455 
1456   Not collective
1457 
1458   Input Parameters:
1459 + prob - The PetscDS
1460 . f    - The test field number
1461 . g    - The field number
1462 . g0 - integrand for the test and basis function term
1463 . g1 - integrand for the test function and basis function gradient term
1464 . g2 - integrand for the test function gradient and basis function term
1465 - g3 - integrand for the test function gradient and basis function gradient term
1466 
1467   Note: We are using a first order FEM model for the weak form:
1468 
1469   \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
1470 
1471 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1472 
1473 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1474 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1475 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1476 $    PetscReal t, const PetscReal x[], PetscScalar g0[])
1477 
1478 + dim - the spatial dimension
1479 . Nf - the number of fields
1480 . uOff - the offset into u[] and u_t[] for each field
1481 . uOff_x - the offset into u_x[] for each field
1482 . u - each field evaluated at the current point
1483 . u_t - the time derivative of each field evaluated at the current point
1484 . u_x - the gradient of each field evaluated at the current point
1485 . aOff - the offset into a[] and a_t[] for each auxiliary field
1486 . aOff_x - the offset into a_x[] for each auxiliary field
1487 . a - each auxiliary field evaluated at the current point
1488 . a_t - the time derivative of each auxiliary field evaluated at the current point
1489 . a_x - the gradient of auxiliary each field evaluated at the current point
1490 . t - current time
1491 . u_tShift - the multiplier a for dF/dU_t
1492 . x - coordinates of the current point
1493 - g0 - output values at the current point
1494 
1495   Level: intermediate
1496 
1497 .seealso: PetscDSGetJacobian()
1498 @*/
1499 PetscErrorCode PetscDSSetDynamicJacobian(PetscDS prob, PetscInt f, PetscInt g,
1500                                          void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1501                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1502                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1503                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g0[]),
1504                                          void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1505                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1506                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1507                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g1[]),
1508                                          void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1509                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1510                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1511                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g2[]),
1512                                          void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1513                                                     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1514                                                     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1515                                                     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g3[]))
1516 {
1517   PetscErrorCode ierr;
1518 
1519   PetscFunctionBegin;
1520   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1521   if (g0) PetscValidFunction(g0, 4);
1522   if (g1) PetscValidFunction(g1, 5);
1523   if (g2) PetscValidFunction(g2, 6);
1524   if (g3) PetscValidFunction(g3, 7);
1525   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1526   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
1527   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
1528   prob->gt[(f*prob->Nf + g)*4+0] = g0;
1529   prob->gt[(f*prob->Nf + g)*4+1] = g1;
1530   prob->gt[(f*prob->Nf + g)*4+2] = g2;
1531   prob->gt[(f*prob->Nf + g)*4+3] = g3;
1532   PetscFunctionReturn(0);
1533 }
1534 
1535 /*@C
1536   PetscDSGetRiemannSolver - Returns the Riemann solver for the given field
1537 
1538   Not collective
1539 
1540   Input Arguments:
1541 + prob - The PetscDS object
1542 - f    - The field number
1543 
1544   Output Argument:
1545 . r    - Riemann solver
1546 
1547   Calling sequence for r:
1548 
1549 $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)
1550 
1551 + dim  - The spatial dimension
1552 . Nf   - The number of fields
1553 . x    - The coordinates at a point on the interface
1554 . n    - The normal vector to the interface
1555 . uL   - The state vector to the left of the interface
1556 . uR   - The state vector to the right of the interface
1557 . flux - output array of flux through the interface
1558 - ctx  - optional user context
1559 
1560   Level: intermediate
1561 
1562 .seealso: PetscDSSetRiemannSolver()
1563 @*/
1564 PetscErrorCode PetscDSGetRiemannSolver(PetscDS prob, PetscInt f,
1565                                        void (**r)(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx))
1566 {
1567   PetscFunctionBegin;
1568   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1569   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);
1570   PetscValidPointer(r, 3);
1571   *r = prob->r[f];
1572   PetscFunctionReturn(0);
1573 }
1574 
1575 /*@C
1576   PetscDSSetRiemannSolver - Sets the Riemann solver for the given field
1577 
1578   Not collective
1579 
1580   Input Arguments:
1581 + prob - The PetscDS object
1582 . f    - The field number
1583 - r    - Riemann solver
1584 
1585   Calling sequence for r:
1586 
1587 $ r(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx)
1588 
1589 + dim  - The spatial dimension
1590 . Nf   - The number of fields
1591 . x    - The coordinates at a point on the interface
1592 . n    - The normal vector to the interface
1593 . uL   - The state vector to the left of the interface
1594 . uR   - The state vector to the right of the interface
1595 . flux - output array of flux through the interface
1596 - ctx  - optional user context
1597 
1598   Level: intermediate
1599 
1600 .seealso: PetscDSGetRiemannSolver()
1601 @*/
1602 PetscErrorCode PetscDSSetRiemannSolver(PetscDS prob, PetscInt f,
1603                                        void (*r)(PetscInt dim, PetscInt Nf, const PetscReal x[], const PetscReal n[], const PetscScalar uL[], const PetscScalar uR[], PetscScalar flux[], void *ctx))
1604 {
1605   PetscErrorCode ierr;
1606 
1607   PetscFunctionBegin;
1608   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1609   if (r) PetscValidFunction(r, 3);
1610   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1611   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1612   prob->r[f] = r;
1613   PetscFunctionReturn(0);
1614 }
1615 
1616 /*@C
1617   PetscDSGetUpdate - Get the pointwise update function for a given field
1618 
1619   Not collective
1620 
1621   Input Parameters:
1622 + prob - The PetscDS
1623 - f    - The field number
1624 
1625   Output Parameters:
1626 + update - update function
1627 
1628   Note: The calling sequence for the callback update is given by:
1629 
1630 $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1631 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1632 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1633 $        PetscReal t, const PetscReal x[], PetscScalar uNew[])
1634 
1635 + dim - the spatial dimension
1636 . Nf - the number of fields
1637 . uOff - the offset into u[] and u_t[] for each field
1638 . uOff_x - the offset into u_x[] for each field
1639 . u - each field evaluated at the current point
1640 . u_t - the time derivative of each field evaluated at the current point
1641 . u_x - the gradient of each field evaluated at the current point
1642 . aOff - the offset into a[] and a_t[] for each auxiliary field
1643 . aOff_x - the offset into a_x[] for each auxiliary field
1644 . a - each auxiliary field evaluated at the current point
1645 . a_t - the time derivative of each auxiliary field evaluated at the current point
1646 . a_x - the gradient of auxiliary each field evaluated at the current point
1647 . t - current time
1648 . x - coordinates of the current point
1649 - uNew - new value for field at the current point
1650 
1651   Level: intermediate
1652 
1653 .seealso: PetscDSSetUpdate(), PetscDSSetResidual()
1654 @*/
1655 PetscErrorCode PetscDSGetUpdate(PetscDS prob, PetscInt f,
1656                                   void (**update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1657                                                   const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1658                                                   const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1659                                                   PetscReal t, const PetscReal x[], PetscScalar uNew[]))
1660 {
1661   PetscFunctionBegin;
1662   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1663   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);
1664   if (update) {PetscValidPointer(update, 3); *update = prob->update[f];}
1665   PetscFunctionReturn(0);
1666 }
1667 
1668 /*@C
1669   PetscDSSetResidual - Set the pointwise update function for a given field
1670 
1671   Not collective
1672 
1673   Input Parameters:
1674 + prob   - The PetscDS
1675 . f      - The field number
1676 - update - update function
1677 
1678   Note: The calling sequence for the callback update is given by:
1679 
1680 $ update(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1681 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1682 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1683 $        PetscReal t, const PetscReal x[], PetscScalar uNew[])
1684 
1685 + dim - the spatial dimension
1686 . Nf - the number of fields
1687 . uOff - the offset into u[] and u_t[] for each field
1688 . uOff_x - the offset into u_x[] for each field
1689 . u - each field evaluated at the current point
1690 . u_t - the time derivative of each field evaluated at the current point
1691 . u_x - the gradient of each field evaluated at the current point
1692 . aOff - the offset into a[] and a_t[] for each auxiliary field
1693 . aOff_x - the offset into a_x[] for each auxiliary field
1694 . a - each auxiliary field evaluated at the current point
1695 . a_t - the time derivative of each auxiliary field evaluated at the current point
1696 . a_x - the gradient of auxiliary each field evaluated at the current point
1697 . t - current time
1698 . x - coordinates of the current point
1699 - uNew - new field values at the current point
1700 
1701   Level: intermediate
1702 
1703 .seealso: PetscDSGetResidual()
1704 @*/
1705 PetscErrorCode PetscDSSetUpdate(PetscDS prob, PetscInt f,
1706                                 void (*update)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1707                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1708                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1709                                                PetscReal t, const PetscReal x[], PetscScalar uNew[]))
1710 {
1711   PetscErrorCode ierr;
1712 
1713   PetscFunctionBegin;
1714   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1715   if (update) PetscValidFunction(update, 3);
1716   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1717   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1718   prob->update[f] = update;
1719   PetscFunctionReturn(0);
1720 }
1721 
1722 PetscErrorCode PetscDSGetContext(PetscDS prob, PetscInt f, void **ctx)
1723 {
1724   PetscFunctionBegin;
1725   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1726   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);
1727   PetscValidPointer(ctx, 3);
1728   *ctx = prob->ctx[f];
1729   PetscFunctionReturn(0);
1730 }
1731 
1732 PetscErrorCode PetscDSSetContext(PetscDS prob, PetscInt f, void *ctx)
1733 {
1734   PetscErrorCode ierr;
1735 
1736   PetscFunctionBegin;
1737   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1738   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1739   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1740   prob->ctx[f] = ctx;
1741   PetscFunctionReturn(0);
1742 }
1743 
1744 /*@C
1745   PetscDSGetBdResidual - Get the pointwise boundary residual function for a given test field
1746 
1747   Not collective
1748 
1749   Input Parameters:
1750 + prob - The PetscDS
1751 - f    - The test field number
1752 
1753   Output Parameters:
1754 + f0 - boundary integrand for the test function term
1755 - f1 - boundary integrand for the test function gradient term
1756 
1757   Note: We are using a first order FEM model for the weak form:
1758 
1759   \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
1760 
1761 The calling sequence for the callbacks f0 and f1 is given by:
1762 
1763 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1764 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1765 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1766 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
1767 
1768 + dim - the spatial dimension
1769 . Nf - the number of fields
1770 . uOff - the offset into u[] and u_t[] for each field
1771 . uOff_x - the offset into u_x[] for each field
1772 . u - each field evaluated at the current point
1773 . u_t - the time derivative of each field evaluated at the current point
1774 . u_x - the gradient of each field evaluated at the current point
1775 . aOff - the offset into a[] and a_t[] for each auxiliary field
1776 . aOff_x - the offset into a_x[] for each auxiliary field
1777 . a - each auxiliary field evaluated at the current point
1778 . a_t - the time derivative of each auxiliary field evaluated at the current point
1779 . a_x - the gradient of auxiliary each field evaluated at the current point
1780 . t - current time
1781 . x - coordinates of the current point
1782 . n - unit normal at the current point
1783 - f0 - output values at the current point
1784 
1785   Level: intermediate
1786 
1787 .seealso: PetscDSSetBdResidual()
1788 @*/
1789 PetscErrorCode PetscDSGetBdResidual(PetscDS prob, PetscInt f,
1790                                     void (**f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1791                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1792                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1793                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[]),
1794                                     void (**f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1795                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1796                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1797                                                 PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f1[]))
1798 {
1799   PetscFunctionBegin;
1800   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1801   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);
1802   if (f0) {PetscValidPointer(f0, 3); *f0 = prob->fBd[f*2+0];}
1803   if (f1) {PetscValidPointer(f1, 4); *f1 = prob->fBd[f*2+1];}
1804   PetscFunctionReturn(0);
1805 }
1806 
1807 /*@C
1808   PetscDSSetBdResidual - Get the pointwise boundary residual function for a given test field
1809 
1810   Not collective
1811 
1812   Input Parameters:
1813 + prob - The PetscDS
1814 . f    - The test field number
1815 . f0 - boundary integrand for the test function term
1816 - f1 - boundary integrand for the test function gradient term
1817 
1818   Note: We are using a first order FEM model for the weak form:
1819 
1820   \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
1821 
1822 The calling sequence for the callbacks f0 and f1 is given by:
1823 
1824 $ f0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1825 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1826 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1827 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[])
1828 
1829 + dim - the spatial dimension
1830 . Nf - the number of fields
1831 . uOff - the offset into u[] and u_t[] for each field
1832 . uOff_x - the offset into u_x[] for each field
1833 . u - each field evaluated at the current point
1834 . u_t - the time derivative of each field evaluated at the current point
1835 . u_x - the gradient of each field evaluated at the current point
1836 . aOff - the offset into a[] and a_t[] for each auxiliary field
1837 . aOff_x - the offset into a_x[] for each auxiliary field
1838 . a - each auxiliary field evaluated at the current point
1839 . a_t - the time derivative of each auxiliary field evaluated at the current point
1840 . a_x - the gradient of auxiliary each field evaluated at the current point
1841 . t - current time
1842 . x - coordinates of the current point
1843 . n - unit normal at the current point
1844 - f0 - output values at the current point
1845 
1846   Level: intermediate
1847 
1848 .seealso: PetscDSGetBdResidual()
1849 @*/
1850 PetscErrorCode PetscDSSetBdResidual(PetscDS prob, PetscInt f,
1851                                     void (*f0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1852                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1853                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1854                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f0[]),
1855                                     void (*f1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1856                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1857                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1858                                                PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar f1[]))
1859 {
1860   PetscErrorCode ierr;
1861 
1862   PetscFunctionBegin;
1863   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1864   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
1865   ierr = PetscDSEnlarge_Static(prob, f+1);CHKERRQ(ierr);
1866   if (f0) {PetscValidFunction(f0, 3); prob->fBd[f*2+0] = f0;}
1867   if (f1) {PetscValidFunction(f1, 4); prob->fBd[f*2+1] = f1;}
1868   PetscFunctionReturn(0);
1869 }
1870 
1871 /*@C
1872   PetscDSGetBdJacobian - Get the pointwise boundary Jacobian function for given test and basis field
1873 
1874   Not collective
1875 
1876   Input Parameters:
1877 + prob - The PetscDS
1878 . f    - The test field number
1879 - g    - The field number
1880 
1881   Output Parameters:
1882 + g0 - integrand for the test and basis function term
1883 . g1 - integrand for the test function and basis function gradient term
1884 . g2 - integrand for the test function gradient and basis function term
1885 - g3 - integrand for the test function gradient and basis function gradient term
1886 
1887   Note: We are using a first order FEM model for the weak form:
1888 
1889   \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
1890 
1891 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1892 
1893 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1894 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1895 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1896 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])
1897 
1898 + dim - the spatial dimension
1899 . Nf - the number of fields
1900 . uOff - the offset into u[] and u_t[] for each field
1901 . uOff_x - the offset into u_x[] for each field
1902 . u - each field evaluated at the current point
1903 . u_t - the time derivative of each field evaluated at the current point
1904 . u_x - the gradient of each field evaluated at the current point
1905 . aOff - the offset into a[] and a_t[] for each auxiliary field
1906 . aOff_x - the offset into a_x[] for each auxiliary field
1907 . a - each auxiliary field evaluated at the current point
1908 . a_t - the time derivative of each auxiliary field evaluated at the current point
1909 . a_x - the gradient of auxiliary each field evaluated at the current point
1910 . t - current time
1911 . u_tShift - the multiplier a for dF/dU_t
1912 . x - coordinates of the current point
1913 . n - normal at the current point
1914 - g0 - output values at the current point
1915 
1916   Level: intermediate
1917 
1918 .seealso: PetscDSSetBdJacobian()
1919 @*/
1920 PetscErrorCode PetscDSGetBdJacobian(PetscDS prob, PetscInt f, PetscInt g,
1921                                     void (**g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1922                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1923                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1924                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g0[]),
1925                                     void (**g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1926                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1927                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1928                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g1[]),
1929                                     void (**g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1930                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1931                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1932                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g2[]),
1933                                     void (**g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1934                                                 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1935                                                 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1936                                                 PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g3[]))
1937 {
1938   PetscFunctionBegin;
1939   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
1940   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);
1941   if ((g < 0) || (g >= prob->Nf)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", g, prob->Nf);
1942   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->gBd[(f*prob->Nf + g)*4+0];}
1943   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->gBd[(f*prob->Nf + g)*4+1];}
1944   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->gBd[(f*prob->Nf + g)*4+2];}
1945   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->gBd[(f*prob->Nf + g)*4+3];}
1946   PetscFunctionReturn(0);
1947 }
1948 
1949 /*@C
1950   PetscDSSetBdJacobian - Set the pointwise boundary Jacobian function for given test and basis field
1951 
1952   Not collective
1953 
1954   Input Parameters:
1955 + prob - The PetscDS
1956 . f    - The test field number
1957 . g    - The field number
1958 . g0 - integrand for the test and basis function term
1959 . g1 - integrand for the test function and basis function gradient term
1960 . g2 - integrand for the test function gradient and basis function term
1961 - g3 - integrand for the test function gradient and basis function gradient term
1962 
1963   Note: We are using a first order FEM model for the weak form:
1964 
1965   \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
1966 
1967 The calling sequence for the callbacks g0, g1, g2 and g3 is given by:
1968 
1969 $ g0(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1970 $    const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1971 $    const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
1972 $    PetscReal t, const PetscReal x[], const PetscReal n[], PetscScalar g0[])
1973 
1974 + dim - the spatial dimension
1975 . Nf - the number of fields
1976 . uOff - the offset into u[] and u_t[] for each field
1977 . uOff_x - the offset into u_x[] for each field
1978 . u - each field evaluated at the current point
1979 . u_t - the time derivative of each field evaluated at the current point
1980 . u_x - the gradient of each field evaluated at the current point
1981 . aOff - the offset into a[] and a_t[] for each auxiliary field
1982 . aOff_x - the offset into a_x[] for each auxiliary field
1983 . a - each auxiliary field evaluated at the current point
1984 . a_t - the time derivative of each auxiliary field evaluated at the current point
1985 . a_x - the gradient of auxiliary each field evaluated at the current point
1986 . t - current time
1987 . u_tShift - the multiplier a for dF/dU_t
1988 . x - coordinates of the current point
1989 . n - normal at the current point
1990 - g0 - output values at the current point
1991 
1992   Level: intermediate
1993 
1994 .seealso: PetscDSGetBdJacobian()
1995 @*/
1996 PetscErrorCode PetscDSSetBdJacobian(PetscDS prob, PetscInt f, PetscInt g,
1997                                     void (*g0)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
1998                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
1999                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2000                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g0[]),
2001                                     void (*g1)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2002                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2003                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2004                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g1[]),
2005                                     void (*g2)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2006                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2007                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2008                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g2[]),
2009                                     void (*g3)(PetscInt dim, PetscInt Nf, PetscInt NfAux,
2010                                                const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
2011                                                const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
2012                                                PetscReal t, PetscReal u_tShift, const PetscReal x[], const PetscReal n[], PetscScalar g3[]))
2013 {
2014   PetscErrorCode ierr;
2015 
2016   PetscFunctionBegin;
2017   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2018   if (g0) PetscValidFunction(g0, 4);
2019   if (g1) PetscValidFunction(g1, 5);
2020   if (g2) PetscValidFunction(g2, 6);
2021   if (g3) PetscValidFunction(g3, 7);
2022   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
2023   if (g < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", g);
2024   ierr = PetscDSEnlarge_Static(prob, PetscMax(f, g)+1);CHKERRQ(ierr);
2025   prob->gBd[(f*prob->Nf + g)*4+0] = g0;
2026   prob->gBd[(f*prob->Nf + g)*4+1] = g1;
2027   prob->gBd[(f*prob->Nf + g)*4+2] = g2;
2028   prob->gBd[(f*prob->Nf + g)*4+3] = g3;
2029   PetscFunctionReturn(0);
2030 }
2031 
2032 /*@
2033   PetscDSGetFieldIndex - Returns the index of the given field
2034 
2035   Not collective
2036 
2037   Input Parameters:
2038 + prob - The PetscDS object
2039 - disc - The discretization object
2040 
2041   Output Parameter:
2042 . f - The field number
2043 
2044   Level: beginner
2045 
2046 .seealso: PetscGetDiscretization(), PetscDSGetNumFields(), PetscDSCreate()
2047 @*/
2048 PetscErrorCode PetscDSGetFieldIndex(PetscDS prob, PetscObject disc, PetscInt *f)
2049 {
2050   PetscInt g;
2051 
2052   PetscFunctionBegin;
2053   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2054   PetscValidPointer(f, 3);
2055   *f = -1;
2056   for (g = 0; g < prob->Nf; ++g) {if (disc == prob->disc[g]) break;}
2057   if (g == prob->Nf) SETERRQ(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Field not found in PetscDS.");
2058   *f = g;
2059   PetscFunctionReturn(0);
2060 }
2061 
2062 /*@
2063   PetscDSGetFieldSize - Returns the size of the given field in the full space basis
2064 
2065   Not collective
2066 
2067   Input Parameters:
2068 + prob - The PetscDS object
2069 - f - The field number
2070 
2071   Output Parameter:
2072 . size - The size
2073 
2074   Level: beginner
2075 
2076 .seealso: PetscDSGetFieldOffset(), PetscDSGetNumFields(), PetscDSCreate()
2077 @*/
2078 PetscErrorCode PetscDSGetFieldSize(PetscDS prob, PetscInt f, PetscInt *size)
2079 {
2080   PetscErrorCode ierr;
2081 
2082   PetscFunctionBegin;
2083   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2084   PetscValidPointer(size, 3);
2085   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);
2086   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2087   *size = prob->Nb[f];
2088   PetscFunctionReturn(0);
2089 }
2090 
2091 /*@
2092   PetscDSGetFieldOffset - Returns the offset of the given field in the full space basis
2093 
2094   Not collective
2095 
2096   Input Parameters:
2097 + prob - The PetscDS object
2098 - f - The field number
2099 
2100   Output Parameter:
2101 . off - The offset
2102 
2103   Level: beginner
2104 
2105 .seealso: PetscDSGetFieldSize(), PetscDSGetNumFields(), PetscDSCreate()
2106 @*/
2107 PetscErrorCode PetscDSGetFieldOffset(PetscDS prob, PetscInt f, PetscInt *off)
2108 {
2109   PetscInt       size, g;
2110   PetscErrorCode ierr;
2111 
2112   PetscFunctionBegin;
2113   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2114   PetscValidPointer(off, 3);
2115   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);
2116   *off = 0;
2117   for (g = 0; g < f; ++g) {
2118     ierr = PetscDSGetFieldSize(prob, g, &size);CHKERRQ(ierr);
2119     *off += size;
2120   }
2121   PetscFunctionReturn(0);
2122 }
2123 
2124 /*@
2125   PetscDSGetDimensions - Returns the size of the approximation space for each field on an evaluation point
2126 
2127   Not collective
2128 
2129   Input Parameter:
2130 . prob - The PetscDS object
2131 
2132   Output Parameter:
2133 . dimensions - The number of dimensions
2134 
2135   Level: beginner
2136 
2137 .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
2138 @*/
2139 PetscErrorCode PetscDSGetDimensions(PetscDS prob, PetscInt *dimensions[])
2140 {
2141   PetscErrorCode ierr;
2142 
2143   PetscFunctionBegin;
2144   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2145   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2146   PetscValidPointer(dimensions, 2);
2147   *dimensions = prob->Nb;
2148   PetscFunctionReturn(0);
2149 }
2150 
2151 /*@
2152   PetscDSGetComponents - Returns the number of components for each field on an evaluation point
2153 
2154   Not collective
2155 
2156   Input Parameter:
2157 . prob - The PetscDS object
2158 
2159   Output Parameter:
2160 . components - The number of components
2161 
2162   Level: beginner
2163 
2164 .seealso: PetscDSGetComponentOffsets(), PetscDSGetNumFields(), PetscDSCreate()
2165 @*/
2166 PetscErrorCode PetscDSGetComponents(PetscDS prob, PetscInt *components[])
2167 {
2168   PetscErrorCode ierr;
2169 
2170   PetscFunctionBegin;
2171   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2172   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2173   PetscValidPointer(components, 2);
2174   *components = prob->Nc;
2175   PetscFunctionReturn(0);
2176 }
2177 
2178 /*@
2179   PetscDSGetComponentOffset - Returns the offset of the given field on an evaluation point
2180 
2181   Not collective
2182 
2183   Input Parameters:
2184 + prob - The PetscDS object
2185 - f - The field number
2186 
2187   Output Parameter:
2188 . off - The offset
2189 
2190   Level: beginner
2191 
2192 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2193 @*/
2194 PetscErrorCode PetscDSGetComponentOffset(PetscDS prob, PetscInt f, PetscInt *off)
2195 {
2196   PetscFunctionBegin;
2197   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2198   PetscValidPointer(off, 3);
2199   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);
2200   *off = prob->off[f];
2201   PetscFunctionReturn(0);
2202 }
2203 
2204 /*@
2205   PetscDSGetComponentOffsets - Returns the offset of each field on an evaluation point
2206 
2207   Not collective
2208 
2209   Input Parameter:
2210 . prob - The PetscDS object
2211 
2212   Output Parameter:
2213 . offsets - The offsets
2214 
2215   Level: beginner
2216 
2217 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2218 @*/
2219 PetscErrorCode PetscDSGetComponentOffsets(PetscDS prob, PetscInt *offsets[])
2220 {
2221   PetscFunctionBegin;
2222   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2223   PetscValidPointer(offsets, 2);
2224   *offsets = prob->off;
2225   PetscFunctionReturn(0);
2226 }
2227 
2228 /*@
2229   PetscDSGetComponentDerivativeOffsets - Returns the offset of each field derivative on an evaluation point
2230 
2231   Not collective
2232 
2233   Input Parameter:
2234 . prob - The PetscDS object
2235 
2236   Output Parameter:
2237 . offsets - The offsets
2238 
2239   Level: beginner
2240 
2241 .seealso: PetscDSGetNumFields(), PetscDSCreate()
2242 @*/
2243 PetscErrorCode PetscDSGetComponentDerivativeOffsets(PetscDS prob, PetscInt *offsets[])
2244 {
2245   PetscFunctionBegin;
2246   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2247   PetscValidPointer(offsets, 2);
2248   *offsets = prob->offDer;
2249   PetscFunctionReturn(0);
2250 }
2251 
2252 /*@C
2253   PetscDSGetTabulation - Return the basis tabulation at quadrature points for the volume discretization
2254 
2255   Not collective
2256 
2257   Input Parameter:
2258 . prob - The PetscDS object
2259 
2260   Output Parameters:
2261 + basis - The basis function tabulation at quadrature points
2262 - basisDer - The basis function derivative tabulation at quadrature points
2263 
2264   Level: intermediate
2265 
2266 .seealso: PetscDSCreate()
2267 @*/
2268 PetscErrorCode PetscDSGetTabulation(PetscDS prob, PetscReal ***basis, PetscReal ***basisDer)
2269 {
2270   PetscErrorCode ierr;
2271 
2272   PetscFunctionBegin;
2273   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2274   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2275   if (basis)    {PetscValidPointer(basis, 2);    *basis    = prob->basis;}
2276   if (basisDer) {PetscValidPointer(basisDer, 3); *basisDer = prob->basisDer;}
2277   PetscFunctionReturn(0);
2278 }
2279 
2280 /*@C
2281   PetscDSGetFaceTabulation - Return the basis tabulation at quadrature points on the faces
2282 
2283   Not collective
2284 
2285   Input Parameter:
2286 . prob - The PetscDS object
2287 
2288   Output Parameters:
2289 + basisFace - The basis function tabulation at quadrature points
2290 - basisDerFace - The basis function derivative tabulation at quadrature points
2291 
2292   Level: intermediate
2293 
2294 .seealso: PetscDSGetTabulation(), PetscDSCreate()
2295 @*/
2296 PetscErrorCode PetscDSGetFaceTabulation(PetscDS prob, PetscReal ***basis, PetscReal ***basisDer)
2297 {
2298   PetscErrorCode ierr;
2299 
2300   PetscFunctionBegin;
2301   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2302   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2303   if (basis)    {PetscValidPointer(basis, 2);    *basis    = prob->basisFace;}
2304   if (basisDer) {PetscValidPointer(basisDer, 3); *basisDer = prob->basisDerFace;}
2305   PetscFunctionReturn(0);
2306 }
2307 
2308 PetscErrorCode PetscDSGetEvaluationArrays(PetscDS prob, PetscScalar **u, PetscScalar **u_t, PetscScalar **u_x)
2309 {
2310   PetscErrorCode ierr;
2311 
2312   PetscFunctionBegin;
2313   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2314   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2315   if (u)   {PetscValidPointer(u, 2);   *u   = prob->u;}
2316   if (u_t) {PetscValidPointer(u_t, 3); *u_t = prob->u_t;}
2317   if (u_x) {PetscValidPointer(u_x, 4); *u_x = prob->u_x;}
2318   PetscFunctionReturn(0);
2319 }
2320 
2321 PetscErrorCode PetscDSGetWeakFormArrays(PetscDS prob, PetscScalar **f0, PetscScalar **f1, PetscScalar **g0, PetscScalar **g1, PetscScalar **g2, PetscScalar **g3)
2322 {
2323   PetscErrorCode ierr;
2324 
2325   PetscFunctionBegin;
2326   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2327   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2328   if (f0) {PetscValidPointer(f0, 2); *f0 = prob->f0;}
2329   if (f1) {PetscValidPointer(f1, 3); *f1 = prob->f1;}
2330   if (g0) {PetscValidPointer(g0, 4); *g0 = prob->g0;}
2331   if (g1) {PetscValidPointer(g1, 5); *g1 = prob->g1;}
2332   if (g2) {PetscValidPointer(g2, 6); *g2 = prob->g2;}
2333   if (g3) {PetscValidPointer(g3, 7); *g3 = prob->g3;}
2334   PetscFunctionReturn(0);
2335 }
2336 
2337 PetscErrorCode PetscDSGetRefCoordArrays(PetscDS prob, PetscReal **x, PetscScalar **refSpaceDer)
2338 {
2339   PetscErrorCode ierr;
2340 
2341   PetscFunctionBegin;
2342   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2343   ierr = PetscDSSetUp(prob);CHKERRQ(ierr);
2344   if (x)           {PetscValidPointer(x, 2);           *x           = prob->x;}
2345   if (refSpaceDer) {PetscValidPointer(refSpaceDer, 3); *refSpaceDer = prob->refSpaceDer;}
2346   PetscFunctionReturn(0);
2347 }
2348 
2349 /*@C
2350   PetscDSAddBoundary - Add a boundary condition to the model
2351 
2352   Input Parameters:
2353 + ds          - The PetscDS object
2354 . type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
2355 . name        - The BC name
2356 . labelname   - The label defining constrained points
2357 . field       - The field to constrain
2358 . numcomps    - The number of constrained field components
2359 . comps       - An array of constrained component numbers
2360 . bcFunc      - A pointwise function giving boundary values
2361 . numids      - The number of DMLabel ids for constrained points
2362 . ids         - An array of ids for constrained points
2363 - ctx         - An optional user context for bcFunc
2364 
2365   Options Database Keys:
2366 + -bc_<boundary name> <num> - Overrides the boundary ids
2367 - -bc_<boundary name>_comp <num> - Overrides the boundary components
2368 
2369   Level: developer
2370 
2371 .seealso: PetscDSGetBoundary()
2372 @*/
2373 PetscErrorCode PetscDSAddBoundary(PetscDS ds, DMBoundaryConditionType type, const char name[], const char labelname[], PetscInt field, PetscInt numcomps, const PetscInt *comps, void (*bcFunc)(void), PetscInt numids, const PetscInt *ids, void *ctx)
2374 {
2375   DSBoundary     b;
2376   PetscErrorCode ierr;
2377 
2378   PetscFunctionBegin;
2379   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2380   ierr = PetscNew(&b);CHKERRQ(ierr);
2381   ierr = PetscStrallocpy(name, (char **) &b->name);CHKERRQ(ierr);
2382   ierr = PetscStrallocpy(labelname, (char **) &b->labelname);CHKERRQ(ierr);
2383   ierr = PetscMalloc1(numcomps, &b->comps);CHKERRQ(ierr);
2384   if (numcomps) {ierr = PetscMemcpy(b->comps, comps, numcomps*sizeof(PetscInt));CHKERRQ(ierr);}
2385   ierr = PetscMalloc1(numids, &b->ids);CHKERRQ(ierr);
2386   if (numids) {ierr = PetscMemcpy(b->ids, ids, numids*sizeof(PetscInt));CHKERRQ(ierr);}
2387   b->type            = type;
2388   b->field           = field;
2389   b->numcomps        = numcomps;
2390   b->func            = bcFunc;
2391   b->numids          = numids;
2392   b->ctx             = ctx;
2393   b->next            = ds->boundary;
2394   ds->boundary       = b;
2395   PetscFunctionReturn(0);
2396 }
2397 
2398 /*@
2399   PetscDSGetNumBoundary - Get the number of registered BC
2400 
2401   Input Parameters:
2402 . ds - The PetscDS object
2403 
2404   Output Parameters:
2405 . numBd - The number of BC
2406 
2407   Level: intermediate
2408 
2409 .seealso: PetscDSAddBoundary(), PetscDSGetBoundary()
2410 @*/
2411 PetscErrorCode PetscDSGetNumBoundary(PetscDS ds, PetscInt *numBd)
2412 {
2413   DSBoundary b = ds->boundary;
2414 
2415   PetscFunctionBegin;
2416   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2417   PetscValidPointer(numBd, 2);
2418   *numBd = 0;
2419   while (b) {++(*numBd); b = b->next;}
2420   PetscFunctionReturn(0);
2421 }
2422 
2423 /*@C
2424   PetscDSGetBoundary - Add a boundary condition to the model
2425 
2426   Input Parameters:
2427 + ds          - The PetscDS object
2428 - bd          - The BC number
2429 
2430   Output Parameters:
2431 + type        - The type of condition, e.g. DM_BC_ESSENTIAL/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
2432 . name        - The BC name
2433 . labelname   - The label defining constrained points
2434 . field       - The field to constrain
2435 . numcomps    - The number of constrained field components
2436 . comps       - An array of constrained component numbers
2437 . bcFunc      - A pointwise function giving boundary values
2438 . numids      - The number of DMLabel ids for constrained points
2439 . ids         - An array of ids for constrained points
2440 - ctx         - An optional user context for bcFunc
2441 
2442   Options Database Keys:
2443 + -bc_<boundary name> <num> - Overrides the boundary ids
2444 - -bc_<boundary name>_comp <num> - Overrides the boundary components
2445 
2446   Level: developer
2447 
2448 .seealso: PetscDSAddBoundary()
2449 @*/
2450 PetscErrorCode PetscDSGetBoundary(PetscDS ds, PetscInt bd, DMBoundaryConditionType *type, const char **name, const char **labelname, PetscInt *field, PetscInt *numcomps, const PetscInt **comps, void (**func)(void), PetscInt *numids, const PetscInt **ids, void **ctx)
2451 {
2452   DSBoundary b    = ds->boundary;
2453   PetscInt   n    = 0;
2454 
2455   PetscFunctionBegin;
2456   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 1);
2457   while (b) {
2458     if (n == bd) break;
2459     b = b->next;
2460     ++n;
2461   }
2462   if (!b) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Boundary %d is not in [0, %d)", bd, n);
2463   if (type) {
2464     PetscValidPointer(type, 3);
2465     *type = b->type;
2466   }
2467   if (name) {
2468     PetscValidPointer(name, 4);
2469     *name = b->name;
2470   }
2471   if (labelname) {
2472     PetscValidPointer(labelname, 5);
2473     *labelname = b->labelname;
2474   }
2475   if (field) {
2476     PetscValidPointer(field, 6);
2477     *field = b->field;
2478   }
2479   if (numcomps) {
2480     PetscValidPointer(numcomps, 7);
2481     *numcomps = b->numcomps;
2482   }
2483   if (comps) {
2484     PetscValidPointer(comps, 8);
2485     *comps = b->comps;
2486   }
2487   if (func) {
2488     PetscValidPointer(func, 9);
2489     *func = b->func;
2490   }
2491   if (numids) {
2492     PetscValidPointer(numids, 10);
2493     *numids = b->numids;
2494   }
2495   if (ids) {
2496     PetscValidPointer(ids, 11);
2497     *ids = b->ids;
2498   }
2499   if (ctx) {
2500     PetscValidPointer(ctx, 12);
2501     *ctx = b->ctx;
2502   }
2503   PetscFunctionReturn(0);
2504 }
2505 
2506 PetscErrorCode PetscDSCopyBoundary(PetscDS probA, PetscDS probB)
2507 {
2508   DSBoundary     b, next, *lastnext;
2509   PetscErrorCode ierr;
2510 
2511   PetscFunctionBegin;
2512   PetscValidHeaderSpecific(probA, PETSCDS_CLASSID, 1);
2513   PetscValidHeaderSpecific(probB, PETSCDS_CLASSID, 2);
2514   if (probA == probB) PetscFunctionReturn(0);
2515   next = probB->boundary;
2516   while (next) {
2517     DSBoundary b = next;
2518 
2519     next = b->next;
2520     ierr = PetscFree(b->comps);CHKERRQ(ierr);
2521     ierr = PetscFree(b->ids);CHKERRQ(ierr);
2522     ierr = PetscFree(b->name);CHKERRQ(ierr);
2523     ierr = PetscFree(b->labelname);CHKERRQ(ierr);
2524     ierr = PetscFree(b);CHKERRQ(ierr);
2525   }
2526   lastnext = &(probB->boundary);
2527   for (b = probA->boundary; b; b = b->next) {
2528     DSBoundary bNew;
2529 
2530     ierr = PetscNew(&bNew);CHKERRQ(ierr);
2531     bNew->numcomps = b->numcomps;
2532     ierr = PetscMalloc1(bNew->numcomps, &bNew->comps);CHKERRQ(ierr);
2533     ierr = PetscMemcpy(bNew->comps, b->comps, bNew->numcomps*sizeof(PetscInt));CHKERRQ(ierr);
2534     bNew->numids = b->numids;
2535     ierr = PetscMalloc1(bNew->numids, &bNew->ids);CHKERRQ(ierr);
2536     ierr = PetscMemcpy(bNew->ids, b->ids, bNew->numids*sizeof(PetscInt));CHKERRQ(ierr);
2537     ierr = PetscStrallocpy(b->labelname,(char **) &(bNew->labelname));CHKERRQ(ierr);
2538     ierr = PetscStrallocpy(b->name,(char **) &(bNew->name));CHKERRQ(ierr);
2539     bNew->ctx   = b->ctx;
2540     bNew->type  = b->type;
2541     bNew->field = b->field;
2542     bNew->func  = b->func;
2543 
2544     *lastnext = bNew;
2545     lastnext = &(bNew->next);
2546   }
2547   PetscFunctionReturn(0);
2548 }
2549 
2550 /*@
2551   PetscDSCopyEquations - Copy all pointwise function pointers to the new problem
2552 
2553   Not collective
2554 
2555   Input Parameter:
2556 . prob - The PetscDS object
2557 
2558   Output Parameter:
2559 . newprob - The PetscDS copy
2560 
2561   Level: intermediate
2562 
2563 .seealso: PetscDSSetResidual(), PetscDSSetJacobian(), PetscDSSetRiemannSolver(), PetscDSSetBdResidual(), PetscDSSetBdJacobian(), PetscDSCreate()
2564 @*/
2565 PetscErrorCode PetscDSCopyEquations(PetscDS prob, PetscDS newprob)
2566 {
2567   PetscInt       Nf, Ng, f, g;
2568   PetscErrorCode ierr;
2569 
2570   PetscFunctionBegin;
2571   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2572   PetscValidHeaderSpecific(newprob, PETSCDS_CLASSID, 2);
2573   ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr);
2574   ierr = PetscDSGetNumFields(newprob, &Ng);CHKERRQ(ierr);
2575   if (Nf != Ng) SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_SIZ, "Number of fields must match %D != %D", Nf, Ng);CHKERRQ(ierr);
2576   for (f = 0; f < Nf; ++f) {
2577     PetscPointFunc   obj;
2578     PetscPointFunc   f0, f1;
2579     PetscPointJac    g0, g1, g2, g3;
2580     PetscBdPointFunc f0Bd, f1Bd;
2581     PetscBdPointJac  g0Bd, g1Bd, g2Bd, g3Bd;
2582     PetscRiemannFunc r;
2583 
2584     ierr = PetscDSGetObjective(prob, f, &obj);CHKERRQ(ierr);
2585     ierr = PetscDSGetResidual(prob, f, &f0, &f1);CHKERRQ(ierr);
2586     ierr = PetscDSGetBdResidual(prob, f, &f0Bd, &f1Bd);CHKERRQ(ierr);
2587     ierr = PetscDSGetRiemannSolver(prob, f, &r);CHKERRQ(ierr);
2588     ierr = PetscDSSetObjective(newprob, f, obj);CHKERRQ(ierr);
2589     ierr = PetscDSSetResidual(newprob, f, f0, f1);CHKERRQ(ierr);
2590     ierr = PetscDSSetBdResidual(newprob, f, f0Bd, f1Bd);CHKERRQ(ierr);
2591     ierr = PetscDSSetRiemannSolver(newprob, f, r);CHKERRQ(ierr);
2592     for (g = 0; g < Nf; ++g) {
2593       ierr = PetscDSGetJacobian(prob, f, g, &g0, &g1, &g2, &g3);CHKERRQ(ierr);
2594       ierr = PetscDSGetBdJacobian(prob, f, g, &g0Bd, &g1Bd, &g2Bd, &g3Bd);CHKERRQ(ierr);
2595       ierr = PetscDSSetJacobian(newprob, f, g, g0, g1, g2, g3);CHKERRQ(ierr);
2596       ierr = PetscDSSetBdJacobian(newprob, f, g, g0Bd, g1Bd, g2Bd, g3Bd);CHKERRQ(ierr);
2597     }
2598   }
2599   PetscFunctionReturn(0);
2600 }
2601 
2602 static PetscErrorCode PetscDSDestroy_Basic(PetscDS prob)
2603 {
2604   PetscErrorCode      ierr;
2605 
2606   PetscFunctionBegin;
2607   ierr = PetscFree(prob->data);CHKERRQ(ierr);
2608   PetscFunctionReturn(0);
2609 }
2610 
2611 static PetscErrorCode PetscDSInitialize_Basic(PetscDS prob)
2612 {
2613   PetscFunctionBegin;
2614   prob->ops->setfromoptions = NULL;
2615   prob->ops->setup          = NULL;
2616   prob->ops->view           = NULL;
2617   prob->ops->destroy        = PetscDSDestroy_Basic;
2618   PetscFunctionReturn(0);
2619 }
2620 
2621 /*MC
2622   PETSCDSBASIC = "basic" - A discrete system with pointwise residual and boundary residual functions
2623 
2624   Level: intermediate
2625 
2626 .seealso: PetscDSType, PetscDSCreate(), PetscDSSetType()
2627 M*/
2628 
2629 PETSC_EXTERN PetscErrorCode PetscDSCreate_Basic(PetscDS prob)
2630 {
2631   PetscDS_Basic *b;
2632   PetscErrorCode      ierr;
2633 
2634   PetscFunctionBegin;
2635   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 1);
2636   ierr       = PetscNewLog(prob, &b);CHKERRQ(ierr);
2637   prob->data = b;
2638 
2639   ierr = PetscDSInitialize_Basic(prob);CHKERRQ(ierr);
2640   PetscFunctionReturn(0);
2641 }
2642