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