xref: /petsc/src/dm/interface/dm.c (revision b9da1bb3453dee27f36fc5f67fa6245b4c0fc22b)
1 #include <petscvec.h>
2 #include <petsc/private/dmimpl.h>      /*I      "petscdm.h"          I*/
3 #include <petsc/private/dmlabelimpl.h> /*I      "petscdmlabel.h"     I*/
4 #include <petsc/private/petscdsimpl.h> /*I      "petscds.h"     I*/
5 #include <petscdmplex.h>
6 #include <petscdmceed.h>
7 #include <petscdmfield.h>
8 #include <petscsf.h>
9 #include <petscds.h>
10 
11 #ifdef PETSC_HAVE_LIBCEED
12   #include <petscfeceed.h>
13 #endif
14 
15 PetscClassId DM_CLASSID;
16 PetscClassId DMLABEL_CLASSID;
17 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_CreateMassMatrix, DM_Load, DM_AdaptInterpolator, DM_ProjectFunction;
18 
19 const char *const DMBoundaryTypes[]          = {"NONE", "GHOSTED", "MIRROR", "PERIODIC", "TWIST", "DMBoundaryType", "DM_BOUNDARY_", NULL};
20 const char *const DMBoundaryConditionTypes[] = {"INVALID", "ESSENTIAL", "NATURAL", "INVALID", "INVALID", "ESSENTIAL_FIELD", "NATURAL_FIELD", "INVALID", "INVALID", "ESSENTIAL_BD_FIELD", "NATURAL_RIEMANN", "DMBoundaryConditionType", "DM_BC_", NULL};
21 const char *const DMBlockingTypes[]          = {"TOPOLOGICAL_POINT", "FIELD_NODE", "DMBlockingType", "DM_BLOCKING_", NULL};
22 const char *const DMPolytopeTypes[] =
23   {"vertex",  "segment",      "tensor_segment", "triangle", "quadrilateral",  "tensor_quad",  "tetrahedron", "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism", "pyramid", "FV_ghost_cell", "interior_ghost_cell",
24    "unknown", "unknown_cell", "unknown_face",   "invalid",  "DMPolytopeType", "DM_POLYTOPE_", NULL};
25 const char *const DMCopyLabelsModes[] = {"replace", "keep", "fail", "DMCopyLabelsMode", "DM_COPY_LABELS_", NULL};
26 
27 /*@
28   DMCreate - Creates an empty `DM` object. `DM`s are the abstract objects in PETSc that mediate between meshes and discretizations and the
29   algebraic solvers, time integrators, and optimization algorithms.
30 
31   Collective
32 
33   Input Parameter:
34 . comm - The communicator for the `DM` object
35 
36   Output Parameter:
37 . dm - The `DM` object
38 
39   Level: beginner
40 
41   Notes:
42   See `DMType` for a brief summary of available `DM`.
43 
44   The type must then be set with `DMSetType()`. If you never call `DMSetType()` it will generate an
45   error when you try to use the dm.
46 
47 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMType`, `DMDACreate()`, `DMDA`, `DMSLICED`, `DMCOMPOSITE`, `DMPLEX`, `DMMOAB`, `DMNETWORK`
48 @*/
49 PetscErrorCode DMCreate(MPI_Comm comm, DM *dm)
50 {
51   DM      v;
52   PetscDS ds;
53 
54   PetscFunctionBegin;
55   PetscAssertPointer(dm, 2);
56 
57   PetscCall(DMInitializePackage());
58   PetscCall(PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView));
59   ((PetscObject)v)->non_cyclic_references = &DMCountNonCyclicReferences;
60   v->setupcalled                          = PETSC_FALSE;
61   v->setfromoptionscalled                 = PETSC_FALSE;
62   v->ltogmap                              = NULL;
63   v->bind_below                           = 0;
64   v->bs                                   = 1;
65   v->coloringtype                         = IS_COLORING_GLOBAL;
66   PetscCall(PetscSFCreate(comm, &v->sf));
67   PetscCall(PetscSFCreate(comm, &v->sectionSF));
68   v->labels                    = NULL;
69   v->adjacency[0]              = PETSC_FALSE;
70   v->adjacency[1]              = PETSC_TRUE;
71   v->depthLabel                = NULL;
72   v->celltypeLabel             = NULL;
73   v->localSection              = NULL;
74   v->globalSection             = NULL;
75   v->defaultConstraint.section = NULL;
76   v->defaultConstraint.mat     = NULL;
77   v->defaultConstraint.bias    = NULL;
78   v->coordinates[0].dim        = PETSC_DEFAULT;
79   v->coordinates[1].dim        = PETSC_DEFAULT;
80   v->sparseLocalize            = PETSC_TRUE;
81   v->dim                       = PETSC_DETERMINE;
82   {
83     PetscInt i;
84     for (i = 0; i < 10; ++i) {
85       v->nullspaceConstructors[i]     = NULL;
86       v->nearnullspaceConstructors[i] = NULL;
87     }
88   }
89   PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
90   PetscCall(DMSetRegionDS(v, NULL, NULL, ds, NULL));
91   PetscCall(PetscDSDestroy(&ds));
92   PetscCall(PetscHMapAuxCreate(&v->auxData));
93   v->dmBC              = NULL;
94   v->coarseMesh        = NULL;
95   v->outputSequenceNum = -1;
96   v->outputSequenceVal = 0.0;
97   PetscCall(DMSetVecType(v, VECSTANDARD));
98   PetscCall(DMSetMatType(v, MATAIJ));
99 
100   *dm = v;
101   PetscFunctionReturn(PETSC_SUCCESS);
102 }
103 
104 /*@
105   DMClone - Creates a `DM` object with the same topology as the original.
106 
107   Collective
108 
109   Input Parameter:
110 . dm - The original `DM` object
111 
112   Output Parameter:
113 . newdm - The new `DM` object
114 
115   Level: beginner
116 
117   Notes:
118   For some `DM` implementations this is a shallow clone, the result of which may share (reference counted) information with its parent. For example,
119   `DMClone()` applied to a `DMPLEX` object will result in a new `DMPLEX` that shares the topology with the original `DMPLEX`. It does not
120   share the `PetscSection` of the original `DM`.
121 
122   The clone is considered set up if the original has been set up.
123 
124   Use `DMConvert()` for a general way to create new `DM` from a given `DM`
125 
126 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMSetType()`, `DMSetLocalSection()`, `DMSetGlobalSection()`, `DMPLEX`, `DMConvert()`
127 @*/
128 PetscErrorCode DMClone(DM dm, DM *newdm)
129 {
130   PetscSF              sf;
131   Vec                  coords;
132   void                *ctx;
133   MatOrderingType      otype;
134   DMReorderDefaultFlag flg;
135   PetscInt             dim, cdim, i;
136 
137   PetscFunctionBegin;
138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
139   PetscAssertPointer(newdm, 2);
140   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), newdm));
141   PetscCall(DMCopyLabels(dm, *newdm, PETSC_COPY_VALUES, PETSC_TRUE, DM_COPY_LABELS_FAIL));
142   (*newdm)->leveldown     = dm->leveldown;
143   (*newdm)->levelup       = dm->levelup;
144   (*newdm)->prealloc_only = dm->prealloc_only;
145   (*newdm)->prealloc_skip = dm->prealloc_skip;
146   PetscCall(PetscFree((*newdm)->vectype));
147   PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*newdm)->vectype));
148   PetscCall(PetscFree((*newdm)->mattype));
149   PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*newdm)->mattype));
150   PetscCall(DMGetDimension(dm, &dim));
151   PetscCall(DMSetDimension(*newdm, dim));
152   PetscTryTypeMethod(dm, clone, newdm);
153   (*newdm)->setupcalled = dm->setupcalled;
154   PetscCall(DMGetPointSF(dm, &sf));
155   PetscCall(DMSetPointSF(*newdm, sf));
156   PetscCall(DMGetApplicationContext(dm, &ctx));
157   PetscCall(DMSetApplicationContext(*newdm, ctx));
158   PetscCall(DMReorderSectionGetDefault(dm, &flg));
159   PetscCall(DMReorderSectionSetDefault(*newdm, flg));
160   PetscCall(DMReorderSectionGetType(dm, &otype));
161   PetscCall(DMReorderSectionSetType(*newdm, otype));
162   for (i = 0; i < 2; ++i) {
163     if (dm->coordinates[i].dm) {
164       DM           ncdm;
165       PetscSection cs;
166       PetscInt     pEnd = -1, pEndMax = -1;
167 
168       PetscCall(DMGetLocalSection(dm->coordinates[i].dm, &cs));
169       if (cs) PetscCall(PetscSectionGetChart(cs, NULL, &pEnd));
170       PetscCallMPI(MPIU_Allreduce(&pEnd, &pEndMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
171       if (pEndMax >= 0) {
172         PetscCall(DMClone(dm->coordinates[i].dm, &ncdm));
173         PetscCall(DMCopyDisc(dm->coordinates[i].dm, ncdm));
174         PetscCall(DMSetLocalSection(ncdm, cs));
175         if (dm->coordinates[i].dm->periodic.setup) {
176           ncdm->periodic.setup = dm->coordinates[i].dm->periodic.setup;
177           PetscCall(ncdm->periodic.setup(ncdm));
178         }
179         if (i) PetscCall(DMSetCellCoordinateDM(*newdm, ncdm));
180         else PetscCall(DMSetCoordinateDM(*newdm, ncdm));
181         PetscCall(DMDestroy(&ncdm));
182       }
183     }
184   }
185   PetscCall(DMGetCoordinateDim(dm, &cdim));
186   PetscCall(DMSetCoordinateDim(*newdm, cdim));
187   PetscCall(DMGetCoordinatesLocal(dm, &coords));
188   if (coords) {
189     PetscCall(DMSetCoordinatesLocal(*newdm, coords));
190   } else {
191     PetscCall(DMGetCoordinates(dm, &coords));
192     if (coords) PetscCall(DMSetCoordinates(*newdm, coords));
193   }
194   PetscCall(DMGetCellCoordinatesLocal(dm, &coords));
195   if (coords) {
196     PetscCall(DMSetCellCoordinatesLocal(*newdm, coords));
197   } else {
198     PetscCall(DMGetCellCoordinates(dm, &coords));
199     if (coords) PetscCall(DMSetCellCoordinates(*newdm, coords));
200   }
201   {
202     const PetscReal *maxCell, *Lstart, *L;
203 
204     PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
205     PetscCall(DMSetPeriodicity(*newdm, maxCell, Lstart, L));
206   }
207   {
208     PetscBool useCone, useClosure;
209 
210     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, &useCone, &useClosure));
211     PetscCall(DMSetAdjacency(*newdm, PETSC_DEFAULT, useCone, useClosure));
212   }
213   PetscFunctionReturn(PETSC_SUCCESS);
214 }
215 
216 /*@
217   DMSetVecType - Sets the type of vector to be created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
218 
219   Logically Collective
220 
221   Input Parameters:
222 + dm    - initial distributed array
223 - ctype - the vector type, for example `VECSTANDARD`, `VECCUDA`, or `VECVIENNACL`
224 
225   Options Database Key:
226 . -dm_vec_type ctype - the type of vector to create
227 
228   Level: intermediate
229 
230 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMDestroy()`, `DMDAInterpolationType`, `VecType`, `DMGetVecType()`, `DMSetMatType()`, `DMGetMatType()`,
231           `VECSTANDARD`, `VECCUDA`, `VECVIENNACL`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`
232 @*/
233 PetscErrorCode DMSetVecType(DM dm, VecType ctype)
234 {
235   char *tmp;
236 
237   PetscFunctionBegin;
238   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
239   PetscAssertPointer(ctype, 2);
240   tmp = (char *)dm->vectype;
241   PetscCall(PetscStrallocpy(ctype, (char **)&dm->vectype));
242   PetscCall(PetscFree(tmp));
243   PetscFunctionReturn(PETSC_SUCCESS);
244 }
245 
246 /*@
247   DMGetVecType - Gets the type of vector created with `DMCreateLocalVector()` and `DMCreateGlobalVector()`
248 
249   Logically Collective
250 
251   Input Parameter:
252 . da - initial distributed array
253 
254   Output Parameter:
255 . ctype - the vector type
256 
257   Level: intermediate
258 
259 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMDestroy()`, `DMDAInterpolationType`, `VecType`, `DMSetMatType()`, `DMGetMatType()`, `DMSetVecType()`
260 @*/
261 PetscErrorCode DMGetVecType(DM da, VecType *ctype)
262 {
263   PetscFunctionBegin;
264   PetscValidHeaderSpecific(da, DM_CLASSID, 1);
265   *ctype = da->vectype;
266   PetscFunctionReturn(PETSC_SUCCESS);
267 }
268 
269 /*@
270   VecGetDM - Gets the `DM` defining the data layout of the vector
271 
272   Not Collective
273 
274   Input Parameter:
275 . v - The `Vec`
276 
277   Output Parameter:
278 . dm - The `DM`
279 
280   Level: intermediate
281 
282   Note:
283   A `Vec` may not have a `DM` associated with it.
284 
285 .seealso: [](ch_dmbase), `DM`, `VecSetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
286 @*/
287 PetscErrorCode VecGetDM(Vec v, DM *dm)
288 {
289   PetscFunctionBegin;
290   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
291   PetscAssertPointer(dm, 2);
292   PetscCall(PetscObjectQuery((PetscObject)v, "__PETSc_dm", (PetscObject *)dm));
293   PetscFunctionReturn(PETSC_SUCCESS);
294 }
295 
296 /*@
297   VecSetDM - Sets the `DM` defining the data layout of the vector.
298 
299   Not Collective
300 
301   Input Parameters:
302 + v  - The `Vec`
303 - dm - The `DM`
304 
305   Level: developer
306 
307   Notes:
308   This is rarely used, generally one uses `DMGetLocalVector()` or  `DMGetGlobalVector()` to create a vector associated with a given `DM`
309 
310   This is NOT the same as `DMCreateGlobalVector()` since it does not change the view methods or perform other customization, but merely sets the `DM` member.
311 
312 .seealso: [](ch_dmbase), `DM`, `VecGetDM()`, `DMGetLocalVector()`, `DMGetGlobalVector()`, `DMSetVecType()`
313 @*/
314 PetscErrorCode VecSetDM(Vec v, DM dm)
315 {
316   PetscFunctionBegin;
317   PetscValidHeaderSpecific(v, VEC_CLASSID, 1);
318   if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
319   PetscCall(PetscObjectCompose((PetscObject)v, "__PETSc_dm", (PetscObject)dm));
320   PetscFunctionReturn(PETSC_SUCCESS);
321 }
322 
323 /*@
324   DMSetISColoringType - Sets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
325 
326   Logically Collective
327 
328   Input Parameters:
329 + dm    - the `DM` context
330 - ctype - the matrix type
331 
332   Options Database Key:
333 . -dm_is_coloring_type - global or local
334 
335   Level: intermediate
336 
337 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
338           `DMGetISColoringType()`, `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
339 @*/
340 PetscErrorCode DMSetISColoringType(DM dm, ISColoringType ctype)
341 {
342   PetscFunctionBegin;
343   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
344   dm->coloringtype = ctype;
345   PetscFunctionReturn(PETSC_SUCCESS);
346 }
347 
348 /*@
349   DMGetISColoringType - Gets the type of coloring, `IS_COLORING_GLOBAL` or `IS_COLORING_LOCAL` that is created by the `DM`
350 
351   Logically Collective
352 
353   Input Parameter:
354 . dm - the `DM` context
355 
356   Output Parameter:
357 . ctype - the matrix type
358 
359   Options Database Key:
360 . -dm_is_coloring_type - global or local
361 
362   Level: intermediate
363 
364 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMGetMatType()`,
365           `ISColoringType`, `IS_COLORING_GLOBAL`, `IS_COLORING_LOCAL`
366 @*/
367 PetscErrorCode DMGetISColoringType(DM dm, ISColoringType *ctype)
368 {
369   PetscFunctionBegin;
370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
371   *ctype = dm->coloringtype;
372   PetscFunctionReturn(PETSC_SUCCESS);
373 }
374 
375 /*@
376   DMSetMatType - Sets the type of matrix created with `DMCreateMatrix()`
377 
378   Logically Collective
379 
380   Input Parameters:
381 + dm    - the `DM` context
382 - ctype - the matrix type, for example `MATMPIAIJ`
383 
384   Options Database Key:
385 . -dm_mat_type ctype - the type of the matrix to create, for example mpiaij
386 
387   Level: intermediate
388 
389 .seealso: [](ch_dmbase), `DM`, `MatType`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMGetMatType()`, `DMCreateGlobalVector()`, `DMCreateLocalVector()`
390 @*/
391 PetscErrorCode DMSetMatType(DM dm, MatType ctype)
392 {
393   char *tmp;
394 
395   PetscFunctionBegin;
396   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
397   PetscAssertPointer(ctype, 2);
398   tmp = (char *)dm->mattype;
399   PetscCall(PetscStrallocpy(ctype, (char **)&dm->mattype));
400   PetscCall(PetscFree(tmp));
401   PetscFunctionReturn(PETSC_SUCCESS);
402 }
403 
404 /*@
405   DMGetMatType - Gets the type of matrix that would be created with `DMCreateMatrix()`
406 
407   Logically Collective
408 
409   Input Parameter:
410 . dm - the `DM` context
411 
412   Output Parameter:
413 . ctype - the matrix type
414 
415   Level: intermediate
416 
417 .seealso: [](ch_dmbase), `DM`, `DMDACreate1d()`, `DMDACreate2d()`, `DMDACreate3d()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixPreallocateOnly()`, `MatType`, `DMSetMatType()`
418 @*/
419 PetscErrorCode DMGetMatType(DM dm, MatType *ctype)
420 {
421   PetscFunctionBegin;
422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
423   *ctype = dm->mattype;
424   PetscFunctionReturn(PETSC_SUCCESS);
425 }
426 
427 /*@
428   MatGetDM - Gets the `DM` defining the data layout of the matrix
429 
430   Not Collective
431 
432   Input Parameter:
433 . A - The `Mat`
434 
435   Output Parameter:
436 . dm - The `DM`
437 
438   Level: intermediate
439 
440   Note:
441   A matrix may not have a `DM` associated with it
442 
443   Developer Note:
444   Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with the `Mat` through a `PetscObjectCompose()` operation
445 
446 .seealso: [](ch_dmbase), `DM`, `MatSetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
447 @*/
448 PetscErrorCode MatGetDM(Mat A, DM *dm)
449 {
450   PetscFunctionBegin;
451   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
452   PetscAssertPointer(dm, 2);
453   PetscCall(PetscObjectQuery((PetscObject)A, "__PETSc_dm", (PetscObject *)dm));
454   PetscFunctionReturn(PETSC_SUCCESS);
455 }
456 
457 /*@
458   MatSetDM - Sets the `DM` defining the data layout of the matrix
459 
460   Not Collective
461 
462   Input Parameters:
463 + A  - The `Mat`
464 - dm - The `DM`
465 
466   Level: developer
467 
468   Note:
469   This is rarely used in practice, rather `DMCreateMatrix()` is used to create a matrix associated with a particular `DM`
470 
471   Developer Note:
472   Since the `Mat` class doesn't know about the `DM` class the `DM` object is associated with
473   the `Mat` through a `PetscObjectCompose()` operation
474 
475 .seealso: [](ch_dmbase), `DM`, `MatGetDM()`, `DMCreateMatrix()`, `DMSetMatType()`
476 @*/
477 PetscErrorCode MatSetDM(Mat A, DM dm)
478 {
479   PetscFunctionBegin;
480   PetscValidHeaderSpecific(A, MAT_CLASSID, 1);
481   if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
482   PetscCall(PetscObjectCompose((PetscObject)A, "__PETSc_dm", (PetscObject)dm));
483   PetscFunctionReturn(PETSC_SUCCESS);
484 }
485 
486 /*@
487   DMSetOptionsPrefix - Sets the prefix prepended to all option names when searching through the options database
488 
489   Logically Collective
490 
491   Input Parameters:
492 + dm     - the `DM` context
493 - prefix - the prefix to prepend
494 
495   Level: advanced
496 
497   Note:
498   A hyphen (-) must NOT be given at the beginning of the prefix name.
499   The first character of all runtime options is AUTOMATICALLY the hyphen.
500 
501 .seealso: [](ch_dmbase), `DM`, `PetscObjectSetOptionsPrefix()`, `DMSetFromOptions()`
502 @*/
503 PetscErrorCode DMSetOptionsPrefix(DM dm, const char prefix[])
504 {
505   PetscFunctionBegin;
506   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
507   PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm, prefix));
508   if (dm->sf) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sf, prefix));
509   if (dm->sectionSF) PetscCall(PetscObjectSetOptionsPrefix((PetscObject)dm->sectionSF, prefix));
510   PetscFunctionReturn(PETSC_SUCCESS);
511 }
512 
513 /*@
514   DMAppendOptionsPrefix - Appends an additional string to an already existing prefix used for searching for
515   `DM` options in the options database.
516 
517   Logically Collective
518 
519   Input Parameters:
520 + dm     - the `DM` context
521 - prefix - the string to append to the current prefix
522 
523   Level: advanced
524 
525   Note:
526   If the `DM` does not currently have an options prefix then this value is used alone as the prefix as if `DMSetOptionsPrefix()` had been called.
527   A hyphen (-) must NOT be given at the beginning of the prefix name.
528   The first character of all runtime options is AUTOMATICALLY the hyphen.
529 
530 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMGetOptionsPrefix()`, `PetscObjectAppendOptionsPrefix()`, `DMSetFromOptions()`
531 @*/
532 PetscErrorCode DMAppendOptionsPrefix(DM dm, const char prefix[])
533 {
534   PetscFunctionBegin;
535   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
536   PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)dm, prefix));
537   PetscFunctionReturn(PETSC_SUCCESS);
538 }
539 
540 /*@
541   DMGetOptionsPrefix - Gets the prefix used for searching for all
542   DM options in the options database.
543 
544   Not Collective
545 
546   Input Parameter:
547 . dm - the `DM` context
548 
549   Output Parameter:
550 . prefix - pointer to the prefix string used is returned
551 
552   Level: advanced
553 
554   Fortran Note:
555   Pass in a string 'prefix' of
556   sufficient length to hold the prefix.
557 
558 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMAppendOptionsPrefix()`, `DMSetFromOptions()`
559 @*/
560 PetscErrorCode DMGetOptionsPrefix(DM dm, const char *prefix[])
561 {
562   PetscFunctionBegin;
563   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
564   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, prefix));
565   PetscFunctionReturn(PETSC_SUCCESS);
566 }
567 
568 static PetscErrorCode DMCountNonCyclicReferences_Internal(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
569 {
570   PetscInt refct = ((PetscObject)dm)->refct;
571 
572   PetscFunctionBegin;
573   *ncrefct = 0;
574   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
575     refct--;
576     if (recurseCoarse) {
577       PetscInt coarseCount;
578 
579       PetscCall(DMCountNonCyclicReferences_Internal(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE, &coarseCount));
580       refct += coarseCount;
581     }
582   }
583   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
584     refct--;
585     if (recurseFine) {
586       PetscInt fineCount;
587 
588       PetscCall(DMCountNonCyclicReferences_Internal(dm->fineMesh, PETSC_FALSE, PETSC_TRUE, &fineCount));
589       refct += fineCount;
590     }
591   }
592   *ncrefct = refct;
593   PetscFunctionReturn(PETSC_SUCCESS);
594 }
595 
596 /* Generic wrapper for DMCountNonCyclicReferences_Internal() */
597 PetscErrorCode DMCountNonCyclicReferences(PetscObject dm, PetscInt *ncrefct)
598 {
599   PetscFunctionBegin;
600   PetscCall(DMCountNonCyclicReferences_Internal((DM)dm, PETSC_TRUE, PETSC_TRUE, ncrefct));
601   PetscFunctionReturn(PETSC_SUCCESS);
602 }
603 
604 PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
605 {
606   DMLabelLink next = dm->labels;
607 
608   PetscFunctionBegin;
609   /* destroy the labels */
610   while (next) {
611     DMLabelLink tmp = next->next;
612 
613     if (next->label == dm->depthLabel) dm->depthLabel = NULL;
614     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
615     PetscCall(DMLabelDestroy(&next->label));
616     PetscCall(PetscFree(next));
617     next = tmp;
618   }
619   dm->labels = NULL;
620   PetscFunctionReturn(PETSC_SUCCESS);
621 }
622 
623 static PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c)
624 {
625   PetscFunctionBegin;
626   c->dim = PETSC_DEFAULT;
627   PetscCall(DMDestroy(&c->dm));
628   PetscCall(VecDestroy(&c->x));
629   PetscCall(VecDestroy(&c->xl));
630   PetscCall(DMFieldDestroy(&c->field));
631   PetscFunctionReturn(PETSC_SUCCESS);
632 }
633 
634 /*@
635   DMDestroy - Destroys a `DM`.
636 
637   Collective
638 
639   Input Parameter:
640 . dm - the `DM` object to destroy
641 
642   Level: developer
643 
644 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
645 @*/
646 PetscErrorCode DMDestroy(DM *dm)
647 {
648   PetscInt cnt;
649 
650   PetscFunctionBegin;
651   if (!*dm) PetscFunctionReturn(PETSC_SUCCESS);
652   PetscValidHeaderSpecific(*dm, DM_CLASSID, 1);
653 
654   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
655   PetscCall(DMCountNonCyclicReferences_Internal(*dm, PETSC_TRUE, PETSC_TRUE, &cnt));
656   --((PetscObject)*dm)->refct;
657   if (--cnt > 0) {
658     *dm = NULL;
659     PetscFunctionReturn(PETSC_SUCCESS);
660   }
661   if (((PetscObject)*dm)->refct < 0) PetscFunctionReturn(PETSC_SUCCESS);
662   ((PetscObject)*dm)->refct = 0;
663 
664   PetscCall(DMClearGlobalVectors(*dm));
665   PetscCall(DMClearLocalVectors(*dm));
666   PetscCall(DMClearNamedGlobalVectors(*dm));
667   PetscCall(DMClearNamedLocalVectors(*dm));
668 
669   /* Destroy the list of hooks */
670   {
671     DMCoarsenHookLink link, next;
672     for (link = (*dm)->coarsenhook; link; link = next) {
673       next = link->next;
674       PetscCall(PetscFree(link));
675     }
676     (*dm)->coarsenhook = NULL;
677   }
678   {
679     DMRefineHookLink link, next;
680     for (link = (*dm)->refinehook; link; link = next) {
681       next = link->next;
682       PetscCall(PetscFree(link));
683     }
684     (*dm)->refinehook = NULL;
685   }
686   {
687     DMSubDomainHookLink link, next;
688     for (link = (*dm)->subdomainhook; link; link = next) {
689       next = link->next;
690       PetscCall(PetscFree(link));
691     }
692     (*dm)->subdomainhook = NULL;
693   }
694   {
695     DMGlobalToLocalHookLink link, next;
696     for (link = (*dm)->gtolhook; link; link = next) {
697       next = link->next;
698       PetscCall(PetscFree(link));
699     }
700     (*dm)->gtolhook = NULL;
701   }
702   {
703     DMLocalToGlobalHookLink link, next;
704     for (link = (*dm)->ltoghook; link; link = next) {
705       next = link->next;
706       PetscCall(PetscFree(link));
707     }
708     (*dm)->ltoghook = NULL;
709   }
710   /* Destroy the work arrays */
711   {
712     DMWorkLink link, next;
713     PetscCheck(!(*dm)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out %p %p", (void *)(*dm)->workout, (*dm)->workout->mem);
714     for (link = (*dm)->workin; link; link = next) {
715       next = link->next;
716       PetscCall(PetscFree(link->mem));
717       PetscCall(PetscFree(link));
718     }
719     (*dm)->workin = NULL;
720   }
721   /* destroy the labels */
722   PetscCall(DMDestroyLabelLinkList_Internal(*dm));
723   /* destroy the fields */
724   PetscCall(DMClearFields(*dm));
725   /* destroy the boundaries */
726   {
727     DMBoundary next = (*dm)->boundary;
728     while (next) {
729       DMBoundary b = next;
730 
731       next = b->next;
732       PetscCall(PetscFree(b));
733     }
734   }
735 
736   PetscCall(PetscObjectDestroy(&(*dm)->dmksp));
737   PetscCall(PetscObjectDestroy(&(*dm)->dmsnes));
738   PetscCall(PetscObjectDestroy(&(*dm)->dmts));
739 
740   if ((*dm)->ctx && (*dm)->ctxdestroy) PetscCall((*(*dm)->ctxdestroy)(&(*dm)->ctx));
741   PetscCall(MatFDColoringDestroy(&(*dm)->fd));
742   PetscCall(ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap));
743   PetscCall(PetscFree((*dm)->vectype));
744   PetscCall(PetscFree((*dm)->mattype));
745 
746   PetscCall(PetscSectionDestroy(&(*dm)->localSection));
747   PetscCall(PetscSectionDestroy(&(*dm)->globalSection));
748   PetscCall(PetscFree((*dm)->reorderSectionType));
749   PetscCall(PetscLayoutDestroy(&(*dm)->map));
750   PetscCall(PetscSectionDestroy(&(*dm)->defaultConstraint.section));
751   PetscCall(MatDestroy(&(*dm)->defaultConstraint.mat));
752   PetscCall(PetscSFDestroy(&(*dm)->sf));
753   PetscCall(PetscSFDestroy(&(*dm)->sectionSF));
754   if ((*dm)->sfNatural) PetscCall(PetscSFDestroy(&(*dm)->sfNatural));
755   PetscCall(PetscObjectDereference((PetscObject)(*dm)->sfMigration));
756   PetscCall(DMClearAuxiliaryVec(*dm));
757   PetscCall(PetscHMapAuxDestroy(&(*dm)->auxData));
758   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) PetscCall(DMSetFineDM((*dm)->coarseMesh, NULL));
759 
760   PetscCall(DMDestroy(&(*dm)->coarseMesh));
761   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) PetscCall(DMSetCoarseDM((*dm)->fineMesh, NULL));
762   PetscCall(DMDestroy(&(*dm)->fineMesh));
763   PetscCall(PetscFree((*dm)->Lstart));
764   PetscCall(PetscFree((*dm)->L));
765   PetscCall(PetscFree((*dm)->maxCell));
766   PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[0]));
767   PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[1]));
768   if ((*dm)->transformDestroy) PetscCall((*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx));
769   PetscCall(DMDestroy(&(*dm)->transformDM));
770   PetscCall(VecDestroy(&(*dm)->transform));
771   for (PetscInt i = 0; i < (*dm)->periodic.num_affines; i++) {
772     PetscCall(VecScatterDestroy(&(*dm)->periodic.affine_to_local[i]));
773     PetscCall(VecDestroy(&(*dm)->periodic.affine[i]));
774   }
775   if ((*dm)->periodic.num_affines > 0) PetscCall(PetscFree2((*dm)->periodic.affine_to_local, (*dm)->periodic.affine));
776 
777   PetscCall(DMClearDS(*dm));
778   PetscCall(DMDestroy(&(*dm)->dmBC));
779   /* if memory was published with SAWs then destroy it */
780   PetscCall(PetscObjectSAWsViewOff((PetscObject)*dm));
781 
782   PetscTryTypeMethod(*dm, destroy);
783   PetscCall(DMMonitorCancel(*dm));
784   PetscCall(DMCeedDestroy(&(*dm)->dmceed));
785 #ifdef PETSC_HAVE_LIBCEED
786   PetscCallCEED(CeedElemRestrictionDestroy(&(*dm)->ceedERestrict));
787   PetscCallCEED(CeedDestroy(&(*dm)->ceed));
788 #endif
789   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
790   PetscCall(PetscHeaderDestroy(dm));
791   PetscFunctionReturn(PETSC_SUCCESS);
792 }
793 
794 /*@
795   DMSetUp - sets up the data structures inside a `DM` object
796 
797   Collective
798 
799   Input Parameter:
800 . dm - the `DM` object to setup
801 
802   Level: intermediate
803 
804   Note:
805   This is usually called after various parameter setting operations and `DMSetFromOptions()` are called on the `DM`
806 
807 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
808 @*/
809 PetscErrorCode DMSetUp(DM dm)
810 {
811   PetscFunctionBegin;
812   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
813   if (dm->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
814   PetscTryTypeMethod(dm, setup);
815   dm->setupcalled = PETSC_TRUE;
816   PetscFunctionReturn(PETSC_SUCCESS);
817 }
818 
819 /*@
820   DMSetFromOptions - sets parameters in a `DM` from the options database
821 
822   Collective
823 
824   Input Parameter:
825 . dm - the `DM` object to set options for
826 
827   Options Database Keys:
828 + -dm_preallocate_only                               - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
829 . -dm_vec_type <type>                                - type of vector to create inside `DM`
830 . -dm_mat_type <type>                                - type of matrix to create inside `DM`
831 . -dm_is_coloring_type                               - <global or local>
832 . -dm_bind_below <n>                                 - bind (force execution on CPU) for `Vec` and `Mat` objects with local size (number of vector entries or matrix rows) below n; currently only supported for `DMDA`
833 . -dm_plex_option_phases <ph0_, ph1_, ...>           - List of prefixes for option processing phases
834 . -dm_plex_filename <str>                            - File containing a mesh
835 . -dm_plex_boundary_filename <str>                   - File containing a mesh boundary
836 . -dm_plex_name <str>                                - Name of the mesh in the file
837 . -dm_plex_shape <shape>                             - The domain shape, such as `BOX`, `SPHERE`, etc.
838 . -dm_plex_cell <ct>                                 - Cell shape
839 . -dm_plex_reference_cell_domain <bool>              - Use a reference cell domain
840 . -dm_plex_dim <dim>                                 - Set the topological dimension
841 . -dm_plex_simplex <bool>                            - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements
842 . -dm_plex_interpolate <bool>                        - `PETSC_TRUE` turns on topological interpolation (creating edges and faces)
843 . -dm_plex_orient <bool>                             - `PETSC_TRUE` turns on topological orientation (flipping edges and faces)
844 . -dm_plex_scale <sc>                                - Scale factor for mesh coordinates
845 . -dm_coord_remap <bool>                             - Map coordinates using a function
846 . -dm_coord_map <mapname>                            - Select a builtin coordinate map
847 . -dm_coord_map_params <p0,p1,p2,...>                - Set coordinate mapping parameters
848 . -dm_plex_box_faces <m,n,p>                         - Number of faces along each dimension
849 . -dm_plex_box_lower <x,y,z>                         - Specify lower-left-bottom coordinates for the box
850 . -dm_plex_box_upper <x,y,z>                         - Specify upper-right-top coordinates for the box
851 . -dm_plex_box_bd <bx,by,bz>                         - Specify the `DMBoundaryType` for each direction
852 . -dm_plex_sphere_radius <r>                         - The sphere radius
853 . -dm_plex_ball_radius <r>                           - Radius of the ball
854 . -dm_plex_cylinder_bd <bz>                          - Boundary type in the z direction
855 . -dm_plex_cylinder_num_wedges <n>                   - Number of wedges around the cylinder
856 . -dm_plex_reorder <order>                           - Reorder the mesh using the specified algorithm
857 . -dm_refine_pre <n>                                 - The number of refinements before distribution
858 . -dm_refine_uniform_pre <bool>                      - Flag for uniform refinement before distribution
859 . -dm_refine_volume_limit_pre <v>                    - The maximum cell volume after refinement before distribution
860 . -dm_refine <n>                                     - The number of refinements after distribution
861 . -dm_extrude <l>                                    - Activate extrusion and specify the number of layers to extrude
862 . -dm_plex_transform_extrude_thickness <t>           - The total thickness of extruded layers
863 . -dm_plex_transform_extrude_use_tensor <bool>       - Use tensor cells when extruding
864 . -dm_plex_transform_extrude_symmetric <bool>        - Extrude layers symmetrically about the surface
865 . -dm_plex_transform_extrude_normal <n0,...,nd>      - Specify the extrusion direction
866 . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
867 . -dm_plex_create_fv_ghost_cells                     - Flag to create finite volume ghost cells on the boundary
868 . -dm_plex_fv_ghost_cells_label <name>               - Label name for ghost cells boundary
869 . -dm_distribute <bool>                              - Flag to redistribute a mesh among processes
870 . -dm_distribute_overlap <n>                         - The size of the overlap halo
871 . -dm_plex_adj_cone <bool>                           - Set adjacency direction
872 . -dm_plex_adj_closure <bool>                        - Set adjacency size
873 . -dm_plex_use_ceed <bool>                           - Use LibCEED as the FEM backend
874 . -dm_plex_check_symmetry                            - Check that the adjacency information in the mesh is symmetric - `DMPlexCheckSymmetry()`
875 . -dm_plex_check_skeleton                            - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - `DMPlexCheckSkeleton()`
876 . -dm_plex_check_faces                               - Check that the faces of each cell give a vertex order this is consistent with what we expect from the cell type - `DMPlexCheckFaces()`
877 . -dm_plex_check_geometry                            - Check that cells have positive volume - `DMPlexCheckGeometry()`
878 . -dm_plex_check_pointsf                             - Check some necessary conditions for `PointSF` - `DMPlexCheckPointSF()`
879 . -dm_plex_check_interface_cones                     - Check points on inter-partition interfaces have conforming order of cone points - `DMPlexCheckInterfaceCones()`
880 - -dm_plex_check_all                                 - Perform all the checks above
881 
882   Level: intermediate
883 
884   Note:
885   For some `DMType` such as `DMDA` this cannot be called after `DMSetUp()` has been called.
886 
887 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
888          `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`,
889          `DMSetOptionsPrefix()`, `DMType`, `DMPLEX`, `DMDA`, `DMSetUp()`
890 @*/
891 PetscErrorCode DMSetFromOptions(DM dm)
892 {
893   char      typeName[256];
894   PetscBool flg;
895 
896   PetscFunctionBegin;
897   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
898   dm->setfromoptionscalled = PETSC_TRUE;
899   if (dm->sf) PetscCall(PetscSFSetFromOptions(dm->sf));
900   if (dm->sectionSF) PetscCall(PetscSFSetFromOptions(dm->sectionSF));
901   if (dm->coordinates[0].dm) PetscCall(DMSetFromOptions(dm->coordinates[0].dm));
902   PetscObjectOptionsBegin((PetscObject)dm);
903   PetscCall(PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL));
904   PetscCall(PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg));
905   if (flg) PetscCall(DMSetVecType(dm, typeName));
906   PetscCall(PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg));
907   if (flg) PetscCall(DMSetMatType(dm, typeName));
908   PetscCall(PetscOptionsEnum("-dm_blocking_type", "Topological point or field node blocking", "DMSetBlockingType", DMBlockingTypes, (PetscEnum)dm->blocking_type, (PetscEnum *)&dm->blocking_type, NULL));
909   PetscCall(PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL));
910   PetscCall(PetscOptionsInt("-dm_bind_below", "Set the size threshold (in entries) below which the Vec is bound to the CPU", "VecBindToCPU", dm->bind_below, &dm->bind_below, &flg));
911   PetscCall(PetscOptionsBool("-dm_ignore_perm_output", "Ignore the local section permutation on output", "DMGetOutputDM", dm->ignorePermOutput, &dm->ignorePermOutput, NULL));
912   PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject);
913   /* process any options handlers added with PetscObjectAddOptionsHandler() */
914   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject));
915   PetscOptionsEnd();
916   PetscFunctionReturn(PETSC_SUCCESS);
917 }
918 
919 /*@
920   DMViewFromOptions - View a `DM` in a particular way based on a request in the options database
921 
922   Collective
923 
924   Input Parameters:
925 + dm   - the `DM` object
926 . obj  - optional object that provides the prefix for the options database (if `NULL` then the prefix in obj is used)
927 - name - option string that is used to activate viewing
928 
929   Level: intermediate
930 
931   Note:
932   See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed
933 
934 .seealso: [](ch_dmbase), `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()`
935 @*/
936 PetscErrorCode DMViewFromOptions(DM dm, PetscObject obj, const char name[])
937 {
938   PetscFunctionBegin;
939   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
940   PetscCall(PetscObjectViewFromOptions((PetscObject)dm, obj, name));
941   PetscFunctionReturn(PETSC_SUCCESS);
942 }
943 
944 /*@
945   DMView - Views a `DM`. Depending on the `PetscViewer` and its `PetscViewerFormat` it may print some ASCII information about the `DM` to the screen or a file or
946   save the `DM` in a binary file to be loaded later or create a visualization of the `DM`
947 
948   Collective
949 
950   Input Parameters:
951 + dm - the `DM` object to view
952 - v  - the viewer
953 
954   Level: beginner
955 
956   Notes:
957 
958   `PetscViewer` = `PETSCVIEWERHDF5` i.e. HDF5 format can be used with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` to save multiple `DMPLEX`
959   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
960   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
961 
962   `PetscViewer` = `PETSCVIEWEREXODUSII` i.e. ExodusII format assumes that element blocks (mapped to "Cell sets" labels)
963   consists of sequentially numbered cells.
964 
965   If `dm` has been distributed, only the part of the `DM` on MPI rank 0 (including "ghost" cells and vertices) will be written.
966 
967   Only TRI, TET, QUAD, and HEX cells are supported.
968 
969   `DMPLEX` only represents geometry while most post-processing software expect that a mesh also provides information on the discretization space. This function assumes that the file represents Lagrange finite elements of order 1 or 2.
970   The order of the mesh shall be set using `PetscViewerExodusIISetOrder()`
971 
972   Variable names can be set and queried using `PetscViewerExodusII[Set/Get][Nodal/Zonal]VariableNames[s]`.
973 
974 .seealso: [](ch_dmbase), `DM`, `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat()`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()`
975 @*/
976 PetscErrorCode DMView(DM dm, PetscViewer v)
977 {
978   PetscBool         isbinary;
979   PetscMPIInt       size;
980   PetscViewerFormat format;
981 
982   PetscFunctionBegin;
983   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
984   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v));
985   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
986   /* Ideally, we would like to have this test on.
987      However, it currently breaks socket viz via GLVis.
988      During DMView(parallel_mesh,glvis_viewer), each
989      process opens a sequential ASCII socket to visualize
990      the local mesh, and PetscObjectView(dm,local_socket)
991      is internally called inside VecView_GLVis, incurring
992      in an error here */
993   /* PetscCheckSameComm(dm,1,v,2); */
994   PetscCall(PetscViewerCheckWritable(v));
995 
996   PetscCall(PetscViewerGetFormat(v, &format));
997   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
998   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
999   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)dm, v));
1000   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary));
1001   if (isbinary) {
1002     PetscInt classid = DM_FILE_CLASSID;
1003     char     type[256];
1004 
1005     PetscCall(PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT));
1006     PetscCall(PetscStrncpy(type, ((PetscObject)dm)->type_name, sizeof(type)));
1007     PetscCall(PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR));
1008   }
1009   PetscTryTypeMethod(dm, view, v);
1010   PetscFunctionReturn(PETSC_SUCCESS);
1011 }
1012 
1013 /*@
1014   DMCreateGlobalVector - Creates a global vector from a `DM` object. A global vector is a parallel vector that has no duplicate values shared between MPI ranks,
1015   that is it has no ghost locations.
1016 
1017   Collective
1018 
1019   Input Parameter:
1020 . dm - the `DM` object
1021 
1022   Output Parameter:
1023 . vec - the global vector
1024 
1025   Level: beginner
1026 
1027 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1028          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1029 @*/
1030 PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec)
1031 {
1032   PetscFunctionBegin;
1033   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1034   PetscAssertPointer(vec, 2);
1035   PetscUseTypeMethod(dm, createglobalvector, vec);
1036   if (PetscDefined(USE_DEBUG)) {
1037     DM vdm;
1038 
1039     PetscCall(VecGetDM(*vec, &vdm));
1040     PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1041   }
1042   PetscFunctionReturn(PETSC_SUCCESS);
1043 }
1044 
1045 /*@
1046   DMCreateLocalVector - Creates a local vector from a `DM` object.
1047 
1048   Not Collective
1049 
1050   Input Parameter:
1051 . dm - the `DM` object
1052 
1053   Output Parameter:
1054 . vec - the local vector
1055 
1056   Level: beginner
1057 
1058   Note:
1059   A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations.
1060 
1061 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
1062          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1063 @*/
1064 PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec)
1065 {
1066   PetscFunctionBegin;
1067   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1068   PetscAssertPointer(vec, 2);
1069   PetscUseTypeMethod(dm, createlocalvector, vec);
1070   if (PetscDefined(USE_DEBUG)) {
1071     DM vdm;
1072 
1073     PetscCall(VecGetDM(*vec, &vdm));
1074     PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_LIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1075   }
1076   PetscFunctionReturn(PETSC_SUCCESS);
1077 }
1078 
1079 /*@
1080   DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`.
1081 
1082   Collective
1083 
1084   Input Parameter:
1085 . dm - the `DM` that provides the mapping
1086 
1087   Output Parameter:
1088 . ltog - the mapping
1089 
1090   Level: advanced
1091 
1092   Notes:
1093   The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()`
1094 
1095   Vectors obtained with  `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do
1096   need to use this function with those objects.
1097 
1098   This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`.
1099 
1100 .seealso: [](ch_dmbase), `DM`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`,
1101           `DMCreateMatrix()`
1102 @*/
1103 PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog)
1104 {
1105   PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1106 
1107   PetscFunctionBegin;
1108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1109   PetscAssertPointer(ltog, 2);
1110   if (!dm->ltogmap) {
1111     PetscSection section, sectionGlobal;
1112 
1113     PetscCall(DMGetLocalSection(dm, &section));
1114     if (section) {
1115       const PetscInt *cdofs;
1116       PetscInt       *ltog;
1117       PetscInt        pStart, pEnd, n, p, k, l;
1118 
1119       PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
1120       PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1121       PetscCall(PetscSectionGetStorageSize(section, &n));
1122       PetscCall(PetscMalloc1(n, &ltog)); /* We want the local+overlap size */
1123       for (p = pStart, l = 0; p < pEnd; ++p) {
1124         PetscInt bdof, cdof, dof, off, c, cind;
1125 
1126         /* Should probably use constrained dofs */
1127         PetscCall(PetscSectionGetDof(section, p, &dof));
1128         PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1129         PetscCall(PetscSectionGetConstraintIndices(section, p, &cdofs));
1130         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &off));
1131         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1132         bdof = cdof && (dof - cdof) ? 1 : dof;
1133         if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof);
1134 
1135         for (c = 0, cind = 0; c < dof; ++c, ++l) {
1136           if (cind < cdof && c == cdofs[cind]) {
1137             ltog[l] = off < 0 ? off - c : -(off + c + 1);
1138             cind++;
1139           } else {
1140             ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind;
1141           }
1142         }
1143       }
1144       /* Must have same blocksize on all procs (some might have no points) */
1145       bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
1146       bsLocal[1] = bs;
1147       PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
1148       if (bsMinMax[0] != bsMinMax[1]) {
1149         bs = 1;
1150       } else {
1151         bs = bsMinMax[0];
1152       }
1153       bs = bs < 0 ? 1 : bs;
1154       /* Must reduce indices by blocksize */
1155       if (bs > 1) {
1156         for (l = 0, k = 0; l < n; l += bs, ++k) {
1157           // Integer division of negative values truncates toward zero(!), not toward negative infinity
1158           ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1);
1159         }
1160         n /= bs;
1161       }
1162       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap));
1163     } else PetscUseTypeMethod(dm, getlocaltoglobalmapping);
1164   }
1165   *ltog = dm->ltogmap;
1166   PetscFunctionReturn(PETSC_SUCCESS);
1167 }
1168 
1169 /*@
1170   DMGetBlockSize - Gets the inherent block size associated with a `DM`
1171 
1172   Not Collective
1173 
1174   Input Parameter:
1175 . dm - the `DM` with block structure
1176 
1177   Output Parameter:
1178 . bs - the block size, 1 implies no exploitable block structure
1179 
1180   Level: intermediate
1181 
1182   Notes:
1183   This might be the number of degrees of freedom at each grid point for a structured grid.
1184 
1185   Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but
1186   rather different locations in the vectors may have a different block size.
1187 
1188 .seealso: [](ch_dmbase), `DM`, `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()`
1189 @*/
1190 PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs)
1191 {
1192   PetscFunctionBegin;
1193   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1194   PetscAssertPointer(bs, 2);
1195   PetscCheck(dm->bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM does not have enough information to provide a block size yet");
1196   *bs = dm->bs;
1197   PetscFunctionReturn(PETSC_SUCCESS);
1198 }
1199 
1200 /*@
1201   DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1202   `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`.
1203 
1204   Collective
1205 
1206   Input Parameters:
1207 + dmc - the `DM` object
1208 - dmf - the second, finer `DM` object
1209 
1210   Output Parameters:
1211 + mat - the interpolation
1212 - vec - the scaling (optional, pass `NULL` if not needed), see `DMCreateInterpolationScale()`
1213 
1214   Level: developer
1215 
1216   Notes:
1217   For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1218   DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation.
1219 
1220   For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate
1221   vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1222 
1223 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()`
1224 @*/
1225 PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec)
1226 {
1227   PetscFunctionBegin;
1228   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1229   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1230   PetscAssertPointer(mat, 3);
1231   PetscCall(PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0));
1232   PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec);
1233   PetscCall(PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0));
1234   PetscFunctionReturn(PETSC_SUCCESS);
1235 }
1236 
1237 /*@
1238   DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is
1239   the transpose of the interpolation between the `DM`.
1240 
1241   Input Parameters:
1242 + dac - `DM` that defines a coarse mesh
1243 . daf - `DM` that defines a fine mesh
1244 - mat - the restriction (or interpolation operator) from fine to coarse
1245 
1246   Output Parameter:
1247 . scale - the scaled vector
1248 
1249   Level: advanced
1250 
1251   Note:
1252   xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual)
1253   restriction. In other words xcoarse is the coarse representation of xfine.
1254 
1255   Developer Note:
1256   If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
1257   on the restriction/interpolation operator to set the bindingpropagates flag to true.
1258 
1259 .seealso: [](ch_dmbase), `DM`, `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, `DMCreateRestriction()`, `DMCreateGlobalVector()`
1260 @*/
1261 PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale)
1262 {
1263   Vec         fine;
1264   PetscScalar one = 1.0;
1265 #if defined(PETSC_HAVE_CUDA)
1266   PetscBool bindingpropagates, isbound;
1267 #endif
1268 
1269   PetscFunctionBegin;
1270   PetscCall(DMCreateGlobalVector(daf, &fine));
1271   PetscCall(DMCreateGlobalVector(dac, scale));
1272   PetscCall(VecSet(fine, one));
1273 #if defined(PETSC_HAVE_CUDA)
1274   /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1275    * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1276    * we'll need to do it for that case, too.*/
1277   PetscCall(VecGetBindingPropagates(fine, &bindingpropagates));
1278   if (bindingpropagates) {
1279     PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE));
1280     PetscCall(VecBoundToCPU(fine, &isbound));
1281     PetscCall(MatBindToCPU(mat, isbound));
1282   }
1283 #endif
1284   PetscCall(MatRestrict(mat, fine, *scale));
1285   PetscCall(VecDestroy(&fine));
1286   PetscCall(VecReciprocal(*scale));
1287   PetscFunctionReturn(PETSC_SUCCESS);
1288 }
1289 
1290 /*@
1291   DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1292   `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`.
1293 
1294   Collective
1295 
1296   Input Parameters:
1297 + dmc - the `DM` object
1298 - dmf - the second, finer `DM` object
1299 
1300   Output Parameter:
1301 . mat - the restriction
1302 
1303   Level: developer
1304 
1305   Note:
1306   This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that
1307   matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object.
1308 
1309 .seealso: [](ch_dmbase), `DM`, `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()`
1310 @*/
1311 PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat)
1312 {
1313   PetscFunctionBegin;
1314   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1315   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1316   PetscAssertPointer(mat, 3);
1317   PetscCall(PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0));
1318   PetscUseTypeMethod(dmc, createrestriction, dmf, mat);
1319   PetscCall(PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0));
1320   PetscFunctionReturn(PETSC_SUCCESS);
1321 }
1322 
1323 /*@
1324   DMCreateInjection - Gets injection matrix between two `DM` objects.
1325 
1326   Collective
1327 
1328   Input Parameters:
1329 + dac - the `DM` object
1330 - daf - the second, finer `DM` object
1331 
1332   Output Parameter:
1333 . mat - the injection
1334 
1335   Level: developer
1336 
1337   Notes:
1338   This is an operator that applied to a vector obtained with `DMCreateGlobalVector()` on the
1339   fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting
1340   the values on the coarse grid points. This compares to the operator obtained by
1341   `DMCreateRestriction()` or the transpose of the operator obtained by
1342   `DMCreateInterpolation()` that uses a "local weighted average" of the values around the
1343   coarse grid point as the coarse grid value.
1344 
1345   For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1346   `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection.
1347 
1348 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`,
1349           `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()`
1350 @*/
1351 PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat)
1352 {
1353   PetscFunctionBegin;
1354   PetscValidHeaderSpecific(dac, DM_CLASSID, 1);
1355   PetscValidHeaderSpecific(daf, DM_CLASSID, 2);
1356   PetscAssertPointer(mat, 3);
1357   PetscCall(PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0));
1358   PetscUseTypeMethod(dac, createinjection, daf, mat);
1359   PetscCall(PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0));
1360   PetscFunctionReturn(PETSC_SUCCESS);
1361 }
1362 
1363 /*@
1364   DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a
1365   a Galerkin finite element model on the `DM`
1366 
1367   Collective
1368 
1369   Input Parameters:
1370 + dmc - the target `DM` object
1371 - dmf - the source `DM` object, can be `NULL`
1372 
1373   Output Parameter:
1374 . mat - the mass matrix
1375 
1376   Level: developer
1377 
1378   Notes:
1379   For `DMPLEX` the finite element model for the `DM` must have been already provided.
1380 
1381   if `dmc` is `dmf` or `NULL`, then x^t M x is an approximation to the L2 norm of the vector x which is obtained by `DMCreateGlobalVector()`
1382 
1383 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1384 @*/
1385 PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1386 {
1387   PetscFunctionBegin;
1388   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1389   if (!dmf) dmf = dmc;
1390   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1391   PetscAssertPointer(mat, 3);
1392   PetscCall(PetscLogEventBegin(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1393   PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat);
1394   PetscCall(PetscLogEventEnd(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1395   PetscFunctionReturn(PETSC_SUCCESS);
1396 }
1397 
1398 /*@
1399   DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM`
1400 
1401   Collective
1402 
1403   Input Parameter:
1404 . dm - the `DM` object
1405 
1406   Output Parameters:
1407 + llm - the local lumped mass matrix, which is a diagonal matrix, represented as a vector
1408 - lm  - the global lumped mass matrix, which is a diagonal matrix, represented as a vector
1409 
1410   Level: developer
1411 
1412   Note:
1413   See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix.
1414 
1415 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1416 @*/
1417 PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *llm, Vec *lm)
1418 {
1419   PetscFunctionBegin;
1420   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1421   if (llm) PetscAssertPointer(llm, 2);
1422   if (lm) PetscAssertPointer(lm, 3);
1423   if (llm || lm) PetscUseTypeMethod(dm, createmassmatrixlumped, llm, lm);
1424   PetscFunctionReturn(PETSC_SUCCESS);
1425 }
1426 
1427 /*@
1428   DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization
1429   of a PDE on the `DM`.
1430 
1431   Collective
1432 
1433   Input Parameters:
1434 + dm    - the `DM` object
1435 - ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL`
1436 
1437   Output Parameter:
1438 . coloring - the coloring
1439 
1440   Level: developer
1441 
1442   Notes:
1443   Coloring of matrices can also be computed directly from the sparse matrix nonzero structure via the `MatColoring` object or from the mesh from which the
1444   matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors).
1445 
1446   This produces a coloring with the distance of 2, see `MatSetColoringDistance()` which can be used for efficiently computing Jacobians with `MatFDColoringCreate()`
1447   For `DMDA` in three dimensions with periodic boundary conditions the number of grid points in each dimension must be divisible by 2*stencil_width + 1,
1448   otherwise an error will be generated.
1449 
1450 .seealso: [](ch_dmbase), `DM`, `ISColoring`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()`
1451 @*/
1452 PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring)
1453 {
1454   PetscFunctionBegin;
1455   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1456   PetscAssertPointer(coloring, 3);
1457   PetscUseTypeMethod(dm, getcoloring, ctype, coloring);
1458   PetscFunctionReturn(PETSC_SUCCESS);
1459 }
1460 
1461 /*@
1462   DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator.
1463 
1464   Collective
1465 
1466   Input Parameter:
1467 . dm - the `DM` object
1468 
1469   Output Parameter:
1470 . mat - the empty Jacobian
1471 
1472   Options Database Key:
1473 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
1474 
1475   Level: beginner
1476 
1477   Notes:
1478   This properly preallocates the number of nonzeros in the sparse matrix so you
1479   do not need to do it yourself.
1480 
1481   By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1482   the nonzero pattern call `DMSetMatrixPreallocateOnly()`
1483 
1484   For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1485   internally by PETSc.
1486 
1487   For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because
1488   `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute
1489 
1490 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()`
1491 @*/
1492 PetscErrorCode DMCreateMatrix(DM dm, Mat *mat)
1493 {
1494   PetscFunctionBegin;
1495   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1496   PetscAssertPointer(mat, 2);
1497   PetscCall(MatInitializePackage());
1498   PetscCall(PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0));
1499   PetscUseTypeMethod(dm, creatematrix, mat);
1500   if (PetscDefined(USE_DEBUG)) {
1501     DM mdm;
1502 
1503     PetscCall(MatGetDM(*mat, &mdm));
1504     PetscCheck(mdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the matrix", ((PetscObject)dm)->type_name);
1505   }
1506   /* Handle nullspace and near nullspace */
1507   if (dm->Nf) {
1508     MatNullSpace nullSpace;
1509     PetscInt     Nf, f;
1510 
1511     PetscCall(DMGetNumFields(dm, &Nf));
1512     for (f = 0; f < Nf; ++f) {
1513       if (dm->nullspaceConstructors[f]) {
1514         PetscCall((*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace));
1515         PetscCall(MatSetNullSpace(*mat, nullSpace));
1516         PetscCall(MatNullSpaceDestroy(&nullSpace));
1517         break;
1518       }
1519     }
1520     for (f = 0; f < Nf; ++f) {
1521       if (dm->nearnullspaceConstructors[f]) {
1522         PetscCall((*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace));
1523         PetscCall(MatSetNearNullSpace(*mat, nullSpace));
1524         PetscCall(MatNullSpaceDestroy(&nullSpace));
1525       }
1526     }
1527   }
1528   PetscCall(PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0));
1529   PetscFunctionReturn(PETSC_SUCCESS);
1530 }
1531 
1532 /*@
1533   DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and
1534   `ISLocalToGlobalMapping` will be properly set, but the data structures to store values in the
1535   matrices will not be preallocated.
1536 
1537   Logically Collective
1538 
1539   Input Parameters:
1540 + dm   - the `DM`
1541 - skip - `PETSC_TRUE` to skip preallocation
1542 
1543   Level: developer
1544 
1545   Note:
1546   This is most useful to reduce initialization costs when `MatSetPreallocationCOO()` and
1547   `MatSetValuesCOO()` will be used.
1548 
1549 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()`
1550 @*/
1551 PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1552 {
1553   PetscFunctionBegin;
1554   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1555   dm->prealloc_skip = skip;
1556   PetscFunctionReturn(PETSC_SUCCESS);
1557 }
1558 
1559 /*@
1560   DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly
1561   preallocated but the nonzero structure and zero values will not be set.
1562 
1563   Logically Collective
1564 
1565   Input Parameters:
1566 + dm   - the `DM`
1567 - only - `PETSC_TRUE` if only want preallocation
1568 
1569   Options Database Key:
1570 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros
1571 
1572   Level: developer
1573 
1574 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()`
1575 @*/
1576 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1577 {
1578   PetscFunctionBegin;
1579   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1580   dm->prealloc_only = only;
1581   PetscFunctionReturn(PETSC_SUCCESS);
1582 }
1583 
1584 /*@
1585   DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix structure will be created
1586   but the array for numerical values will not be allocated.
1587 
1588   Logically Collective
1589 
1590   Input Parameters:
1591 + dm   - the `DM`
1592 - only - `PETSC_TRUE` if you only want matrix structure
1593 
1594   Level: developer
1595 
1596 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()`
1597 @*/
1598 PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1599 {
1600   PetscFunctionBegin;
1601   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1602   dm->structure_only = only;
1603   PetscFunctionReturn(PETSC_SUCCESS);
1604 }
1605 
1606 /*@
1607   DMSetBlockingType - set the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1608 
1609   Logically Collective
1610 
1611   Input Parameters:
1612 + dm    - the `DM`
1613 - btype - block by topological point or field node
1614 
1615   Options Database Key:
1616 . -dm_blocking_type [topological_point, field_node] - use topological point blocking or field node blocking
1617 
1618   Level: advanced
1619 
1620 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1621 @*/
1622 PetscErrorCode DMSetBlockingType(DM dm, DMBlockingType btype)
1623 {
1624   PetscFunctionBegin;
1625   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1626   dm->blocking_type = btype;
1627   PetscFunctionReturn(PETSC_SUCCESS);
1628 }
1629 
1630 /*@
1631   DMGetBlockingType - get the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1632 
1633   Not Collective
1634 
1635   Input Parameter:
1636 . dm - the `DM`
1637 
1638   Output Parameter:
1639 . btype - block by topological point or field node
1640 
1641   Level: advanced
1642 
1643 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1644 @*/
1645 PetscErrorCode DMGetBlockingType(DM dm, DMBlockingType *btype)
1646 {
1647   PetscFunctionBegin;
1648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1649   PetscAssertPointer(btype, 2);
1650   *btype = dm->blocking_type;
1651   PetscFunctionReturn(PETSC_SUCCESS);
1652 }
1653 
1654 /*@C
1655   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with `DMRestoreWorkArray()`
1656 
1657   Not Collective
1658 
1659   Input Parameters:
1660 + dm    - the `DM` object
1661 . count - The minimum size
1662 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, or `MPIU_INT`)
1663 
1664   Output Parameter:
1665 . mem - the work array
1666 
1667   Level: developer
1668 
1669   Notes:
1670   A `DM` may stash the array between instantiations so using this routine may be more efficient than calling `PetscMalloc()`
1671 
1672   The array may contain nonzero values
1673 
1674 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()`
1675 @*/
1676 PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1677 {
1678   DMWorkLink  link;
1679   PetscMPIInt dsize;
1680 
1681   PetscFunctionBegin;
1682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1683   PetscAssertPointer(mem, 4);
1684   if (!count) {
1685     *(void **)mem = NULL;
1686     PetscFunctionReturn(PETSC_SUCCESS);
1687   }
1688   if (dm->workin) {
1689     link       = dm->workin;
1690     dm->workin = dm->workin->next;
1691   } else {
1692     PetscCall(PetscNew(&link));
1693   }
1694   /* Avoid MPI_Type_size for most used datatypes
1695      Get size directly */
1696   if (dtype == MPIU_INT) dsize = sizeof(PetscInt);
1697   else if (dtype == MPIU_REAL) dsize = sizeof(PetscReal);
1698 #if defined(PETSC_USE_64BIT_INDICES)
1699   else if (dtype == MPI_INT) dsize = sizeof(int);
1700 #endif
1701 #if defined(PETSC_USE_COMPLEX)
1702   else if (dtype == MPIU_SCALAR) dsize = sizeof(PetscScalar);
1703 #endif
1704   else PetscCallMPI(MPI_Type_size(dtype, &dsize));
1705 
1706   if (((size_t)dsize * count) > link->bytes) {
1707     PetscCall(PetscFree(link->mem));
1708     PetscCall(PetscMalloc(dsize * count, &link->mem));
1709     link->bytes = dsize * count;
1710   }
1711   link->next    = dm->workout;
1712   dm->workout   = link;
1713   *(void **)mem = link->mem;
1714   PetscFunctionReturn(PETSC_SUCCESS);
1715 }
1716 
1717 /*@C
1718   DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()`
1719 
1720   Not Collective
1721 
1722   Input Parameters:
1723 + dm    - the `DM` object
1724 . count - The minimum size
1725 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, `MPIU_INT`
1726 
1727   Output Parameter:
1728 . mem - the work array
1729 
1730   Level: developer
1731 
1732   Developer Note:
1733   count and dtype are ignored, they are only needed for `DMGetWorkArray()`
1734 
1735 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()`
1736 @*/
1737 PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1738 {
1739   DMWorkLink *p, link;
1740 
1741   PetscFunctionBegin;
1742   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1743   PetscAssertPointer(mem, 4);
1744   (void)count;
1745   (void)dtype;
1746   if (!*(void **)mem) PetscFunctionReturn(PETSC_SUCCESS);
1747   for (p = &dm->workout; (link = *p); p = &link->next) {
1748     if (link->mem == *(void **)mem) {
1749       *p            = link->next;
1750       link->next    = dm->workin;
1751       dm->workin    = link;
1752       *(void **)mem = NULL;
1753       PetscFunctionReturn(PETSC_SUCCESS);
1754     }
1755   }
1756   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Array was not checked out");
1757 }
1758 
1759 /*@C
1760   DMSetNullSpaceConstructor - Provide a callback function which constructs the nullspace for a given field, defined with `DMAddField()`, when function spaces
1761   are joined or split, such as in `DMCreateSubDM()`
1762 
1763   Logically Collective; No Fortran Support
1764 
1765   Input Parameters:
1766 + dm     - The `DM`
1767 . field  - The field number for the nullspace
1768 - nullsp - A callback to create the nullspace
1769 
1770   Calling sequence of `nullsp`:
1771 + dm        - The present `DM`
1772 . origField - The field number given above, in the original `DM`
1773 . field     - The field number in dm
1774 - nullSpace - The nullspace for the given field
1775 
1776   Level: intermediate
1777 
1778 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1779 @*/
1780 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1781 {
1782   PetscFunctionBegin;
1783   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1784   PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field);
1785   dm->nullspaceConstructors[field] = nullsp;
1786   PetscFunctionReturn(PETSC_SUCCESS);
1787 }
1788 
1789 /*@C
1790   DMGetNullSpaceConstructor - Return the callback function which constructs the nullspace for a given field, defined with `DMAddField()`
1791 
1792   Not Collective; No Fortran Support
1793 
1794   Input Parameters:
1795 + dm    - The `DM`
1796 - field - The field number for the nullspace
1797 
1798   Output Parameter:
1799 . nullsp - A callback to create the nullspace
1800 
1801   Calling sequence of `nullsp`:
1802 + dm        - The present DM
1803 . origField - The field number given above, in the original DM
1804 . field     - The field number in dm
1805 - nullSpace - The nullspace for the given field
1806 
1807   Level: intermediate
1808 
1809 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNullSpaceConstructor()`, `DMSetNearNullSpaceConstructor()`, `DMGetNearNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
1810 @*/
1811 PetscErrorCode DMGetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1812 {
1813   PetscFunctionBegin;
1814   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1815   PetscAssertPointer(nullsp, 3);
1816   PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field);
1817   *nullsp = dm->nullspaceConstructors[field];
1818   PetscFunctionReturn(PETSC_SUCCESS);
1819 }
1820 
1821 /*@C
1822   DMSetNearNullSpaceConstructor - Provide a callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1823 
1824   Logically Collective; No Fortran Support
1825 
1826   Input Parameters:
1827 + dm     - The `DM`
1828 . field  - The field number for the nullspace
1829 - nullsp - A callback to create the near-nullspace
1830 
1831   Calling sequence of `nullsp`:
1832 + dm        - The present `DM`
1833 . origField - The field number given above, in the original `DM`
1834 . field     - The field number in dm
1835 - nullSpace - The nullspace for the given field
1836 
1837   Level: intermediate
1838 
1839 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`, `DMCreateSuperDM()`,
1840           `MatNullSpace`
1841 @*/
1842 PetscErrorCode DMSetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1843 {
1844   PetscFunctionBegin;
1845   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1846   PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field);
1847   dm->nearnullspaceConstructors[field] = nullsp;
1848   PetscFunctionReturn(PETSC_SUCCESS);
1849 }
1850 
1851 /*@C
1852   DMGetNearNullSpaceConstructor - Return the callback function which constructs the near-nullspace for a given field, defined with `DMAddField()`
1853 
1854   Not Collective; No Fortran Support
1855 
1856   Input Parameters:
1857 + dm    - The `DM`
1858 - field - The field number for the nullspace
1859 
1860   Output Parameter:
1861 . nullsp - A callback to create the near-nullspace
1862 
1863   Calling sequence of `nullsp`:
1864 + dm        - The present `DM`
1865 . origField - The field number given above, in the original `DM`
1866 . field     - The field number in dm
1867 - nullSpace - The nullspace for the given field
1868 
1869   Level: intermediate
1870 
1871 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMSetNearNullSpaceConstructor()`, `DMSetNullSpaceConstructor()`, `DMGetNullSpaceConstructor()`, `DMCreateSubDM()`,
1872           `MatNullSpace`, `DMCreateSuperDM()`
1873 @*/
1874 PetscErrorCode DMGetNearNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (**nullsp)(DM dm, PetscInt origField, PetscInt field, MatNullSpace *nullSpace))
1875 {
1876   PetscFunctionBegin;
1877   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1878   PetscAssertPointer(nullsp, 3);
1879   PetscCheck(field < 10, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %" PetscInt_FMT " >= 10 fields", field);
1880   *nullsp = dm->nearnullspaceConstructors[field];
1881   PetscFunctionReturn(PETSC_SUCCESS);
1882 }
1883 
1884 /*@C
1885   DMCreateFieldIS - Creates a set of `IS` objects with the global indices of dofs for each field defined with `DMAddField()`
1886 
1887   Not Collective; No Fortran Support
1888 
1889   Input Parameter:
1890 . dm - the `DM` object
1891 
1892   Output Parameters:
1893 + numFields  - The number of fields (or `NULL` if not requested)
1894 . fieldNames - The number of each field (or `NULL` if not requested)
1895 - fields     - The global indices for each field (or `NULL` if not requested)
1896 
1897   Level: intermediate
1898 
1899   Note:
1900   The user is responsible for freeing all requested arrays. In particular, every entry of `fieldNames` should be freed with
1901   `PetscFree()`, every entry of `fields` should be destroyed with `ISDestroy()`, and both arrays should be freed with
1902   `PetscFree()`.
1903 
1904   Developer Note:
1905   It is not clear why both this function and `DMCreateFieldDecomposition()` exist. Having two seems redundant and confusing. This function should
1906   likely be removed.
1907 
1908 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1909           `DMCreateFieldDecomposition()`
1910 @*/
1911 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1912 {
1913   PetscSection section, sectionGlobal;
1914 
1915   PetscFunctionBegin;
1916   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1917   if (numFields) {
1918     PetscAssertPointer(numFields, 2);
1919     *numFields = 0;
1920   }
1921   if (fieldNames) {
1922     PetscAssertPointer(fieldNames, 3);
1923     *fieldNames = NULL;
1924   }
1925   if (fields) {
1926     PetscAssertPointer(fields, 4);
1927     *fields = NULL;
1928   }
1929   PetscCall(DMGetLocalSection(dm, &section));
1930   if (section) {
1931     PetscInt *fieldSizes, *fieldNc, **fieldIndices;
1932     PetscInt  nF, f, pStart, pEnd, p;
1933 
1934     PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
1935     PetscCall(PetscSectionGetNumFields(section, &nF));
1936     PetscCall(PetscMalloc3(nF, &fieldSizes, nF, &fieldNc, nF, &fieldIndices));
1937     PetscCall(PetscSectionGetChart(sectionGlobal, &pStart, &pEnd));
1938     for (f = 0; f < nF; ++f) {
1939       fieldSizes[f] = 0;
1940       PetscCall(PetscSectionGetFieldComponents(section, f, &fieldNc[f]));
1941     }
1942     for (p = pStart; p < pEnd; ++p) {
1943       PetscInt gdof;
1944 
1945       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
1946       if (gdof > 0) {
1947         for (f = 0; f < nF; ++f) {
1948           PetscInt fdof, fcdof, fpdof;
1949 
1950           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
1951           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
1952           fpdof = fdof - fcdof;
1953           if (fpdof && fpdof != fieldNc[f]) {
1954             /* Layout does not admit a pointwise block size */
1955             fieldNc[f] = 1;
1956           }
1957           fieldSizes[f] += fpdof;
1958         }
1959       }
1960     }
1961     for (f = 0; f < nF; ++f) {
1962       PetscCall(PetscMalloc1(fieldSizes[f], &fieldIndices[f]));
1963       fieldSizes[f] = 0;
1964     }
1965     for (p = pStart; p < pEnd; ++p) {
1966       PetscInt gdof, goff;
1967 
1968       PetscCall(PetscSectionGetDof(sectionGlobal, p, &gdof));
1969       if (gdof > 0) {
1970         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &goff));
1971         for (f = 0; f < nF; ++f) {
1972           PetscInt fdof, fcdof, fc;
1973 
1974           PetscCall(PetscSectionGetFieldDof(section, p, f, &fdof));
1975           PetscCall(PetscSectionGetFieldConstraintDof(section, p, f, &fcdof));
1976           for (fc = 0; fc < fdof - fcdof; ++fc, ++fieldSizes[f]) fieldIndices[f][fieldSizes[f]] = goff++;
1977         }
1978       }
1979     }
1980     if (numFields) *numFields = nF;
1981     if (fieldNames) {
1982       PetscCall(PetscMalloc1(nF, fieldNames));
1983       for (f = 0; f < nF; ++f) {
1984         const char *fieldName;
1985 
1986         PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
1987         PetscCall(PetscStrallocpy(fieldName, &(*fieldNames)[f]));
1988       }
1989     }
1990     if (fields) {
1991       PetscCall(PetscMalloc1(nF, fields));
1992       for (f = 0; f < nF; ++f) {
1993         PetscInt bs, in[2], out[2];
1994 
1995         PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]));
1996         in[0] = -fieldNc[f];
1997         in[1] = fieldNc[f];
1998         PetscCallMPI(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
1999         bs = (-out[0] == out[1]) ? out[1] : 1;
2000         PetscCall(ISSetBlockSize((*fields)[f], bs));
2001       }
2002     }
2003     PetscCall(PetscFree3(fieldSizes, fieldNc, fieldIndices));
2004   } else PetscTryTypeMethod(dm, createfieldis, numFields, fieldNames, fields);
2005   PetscFunctionReturn(PETSC_SUCCESS);
2006 }
2007 
2008 /*@C
2009   DMCreateFieldDecomposition - Returns a list of `IS` objects defining a decomposition of a problem into subproblems
2010   corresponding to different fields.
2011 
2012   Not Collective; No Fortran Support
2013 
2014   Input Parameter:
2015 . dm - the `DM` object
2016 
2017   Output Parameters:
2018 + len      - The number of fields (or `NULL` if not requested)
2019 . namelist - The name for each field (or `NULL` if not requested)
2020 . islist   - The global indices for each field (or `NULL` if not requested)
2021 - dmlist   - The `DM`s for each field subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined)
2022 
2023   Level: intermediate
2024 
2025   Notes:
2026   Each `IS` contains the global indices of the dofs of the corresponding field, defined by
2027   `DMAddField()`. The optional list of `DM`s define the `DM` for each subproblem.
2028 
2029   The same as `DMCreateFieldIS()` but also returns a `DM` for each field.
2030 
2031   The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with
2032   `PetscFree()`, every entry of `islist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`,
2033   and all of the arrays should be freed with `PetscFree()`.
2034 
2035   Developer Notes:
2036   It is not clear why this function and `DMCreateFieldIS()` exist. Having two seems redundant and confusing.
2037 
2038   Unlike  `DMRefine()`, `DMCoarsen()`, and `DMCreateDomainDecomposition()` this provides no mechanism to provide hooks that are called after the
2039   decomposition is computed.
2040 
2041 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMCreateFieldIS()`, `DMCreateSubDM()`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`
2042 @*/
2043 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
2044 {
2045   PetscFunctionBegin;
2046   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2047   if (len) {
2048     PetscAssertPointer(len, 2);
2049     *len = 0;
2050   }
2051   if (namelist) {
2052     PetscAssertPointer(namelist, 3);
2053     *namelist = NULL;
2054   }
2055   if (islist) {
2056     PetscAssertPointer(islist, 4);
2057     *islist = NULL;
2058   }
2059   if (dmlist) {
2060     PetscAssertPointer(dmlist, 5);
2061     *dmlist = NULL;
2062   }
2063   /*
2064    Is it a good idea to apply the following check across all impls?
2065    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2066    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2067    */
2068   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2069   if (!dm->ops->createfielddecomposition) {
2070     PetscSection section;
2071     PetscInt     numFields, f;
2072 
2073     PetscCall(DMGetLocalSection(dm, &section));
2074     if (section) PetscCall(PetscSectionGetNumFields(section, &numFields));
2075     if (section && numFields && dm->ops->createsubdm) {
2076       if (len) *len = numFields;
2077       if (namelist) PetscCall(PetscMalloc1(numFields, namelist));
2078       if (islist) PetscCall(PetscMalloc1(numFields, islist));
2079       if (dmlist) PetscCall(PetscMalloc1(numFields, dmlist));
2080       for (f = 0; f < numFields; ++f) {
2081         const char *fieldName;
2082 
2083         PetscCall(DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL));
2084         if (namelist) {
2085           PetscCall(PetscSectionGetFieldName(section, f, &fieldName));
2086           PetscCall(PetscStrallocpy(fieldName, &(*namelist)[f]));
2087         }
2088       }
2089     } else {
2090       PetscCall(DMCreateFieldIS(dm, len, namelist, islist));
2091       /* By default there are no DMs associated with subproblems. */
2092       if (dmlist) *dmlist = NULL;
2093     }
2094   } else PetscUseTypeMethod(dm, createfielddecomposition, len, namelist, islist, dmlist);
2095   PetscFunctionReturn(PETSC_SUCCESS);
2096 }
2097 
2098 /*@
2099   DMCreateSubDM - Returns an `IS` and `DM` encapsulating a subproblem defined by the fields passed in.
2100   The fields are defined by `DMCreateFieldIS()`.
2101 
2102   Not collective
2103 
2104   Input Parameters:
2105 + dm        - The `DM` object
2106 . numFields - The number of fields to select
2107 - fields    - The field numbers of the selected fields
2108 
2109   Output Parameters:
2110 + is    - The global indices for all the degrees of freedom in the new sub `DM`, use `NULL` if not needed
2111 - subdm - The `DM` for the subproblem, use `NULL` if not needed
2112 
2113   Level: intermediate
2114 
2115   Note:
2116   You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2117 
2118 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldIS()`, `DMCreateFieldDecomposition()`, `DMAddField()`, `DMCreateSuperDM()`, `IS`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
2119 @*/
2120 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, const PetscInt fields[], IS *is, DM *subdm)
2121 {
2122   PetscFunctionBegin;
2123   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2124   PetscAssertPointer(fields, 3);
2125   if (is) PetscAssertPointer(is, 4);
2126   if (subdm) PetscAssertPointer(subdm, 5);
2127   PetscUseTypeMethod(dm, createsubdm, numFields, fields, is, subdm);
2128   PetscFunctionReturn(PETSC_SUCCESS);
2129 }
2130 
2131 /*@C
2132   DMCreateSuperDM - Returns an arrays of `IS` and `DM` encapsulating a superproblem defined by multiple `DM`s passed in.
2133 
2134   Not collective
2135 
2136   Input Parameters:
2137 + dms - The `DM` objects
2138 - n   - The number of `DM`s
2139 
2140   Output Parameters:
2141 + is      - The global indices for each of subproblem within the super `DM`, or NULL
2142 - superdm - The `DM` for the superproblem
2143 
2144   Level: intermediate
2145 
2146   Note:
2147   You need to call `DMPlexSetMigrationSF()` on the original `DM` if you want the Global-To-Natural map to be automatically constructed
2148 
2149 .seealso: [](ch_dmbase), `DM`, `DMCreateSubDM()`, `DMPlexSetMigrationSF()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`, `DMCreateDomainDecomposition()`
2150 @*/
2151 PetscErrorCode DMCreateSuperDM(DM dms[], PetscInt n, IS *is[], DM *superdm)
2152 {
2153   PetscInt i;
2154 
2155   PetscFunctionBegin;
2156   PetscAssertPointer(dms, 1);
2157   for (i = 0; i < n; ++i) PetscValidHeaderSpecific(dms[i], DM_CLASSID, 1);
2158   if (is) PetscAssertPointer(is, 3);
2159   PetscAssertPointer(superdm, 4);
2160   PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of DMs must be nonnegative: %" PetscInt_FMT, n);
2161   if (n) {
2162     DM dm = dms[0];
2163     PetscCheck(dm->ops->createsuperdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No method createsuperdm for DM of type %s", ((PetscObject)dm)->type_name);
2164     PetscCall((*dm->ops->createsuperdm)(dms, n, is, superdm));
2165   }
2166   PetscFunctionReturn(PETSC_SUCCESS);
2167 }
2168 
2169 /*@C
2170   DMCreateDomainDecomposition - Returns lists of `IS` objects defining a decomposition of a
2171   problem into subproblems corresponding to restrictions to pairs of nested subdomains.
2172 
2173   Not Collective
2174 
2175   Input Parameter:
2176 . dm - the `DM` object
2177 
2178   Output Parameters:
2179 + n           - The number of subproblems in the domain decomposition (or `NULL` if not requested)
2180 . namelist    - The name for each subdomain (or `NULL` if not requested)
2181 . innerislist - The global indices for each inner subdomain (or `NULL`, if not requested)
2182 . outerislist - The global indices for each outer subdomain (or `NULL`, if not requested)
2183 - dmlist      - The `DM`s for each subdomain subproblem (or `NULL`, if not requested; if `NULL` is returned, no `DM`s are defined)
2184 
2185   Level: intermediate
2186 
2187   Notes:
2188   Each `IS` contains the global indices of the dofs of the corresponding subdomains with in the
2189   dofs of the original `DM`. The inner subdomains conceptually define a nonoverlapping
2190   covering, while outer subdomains can overlap.
2191 
2192   The optional list of `DM`s define a `DM` for each subproblem.
2193 
2194   The user is responsible for freeing all requested arrays. In particular, every entry of `namelist` should be freed with
2195   `PetscFree()`, every entry of `innerislist` and `outerislist` should be destroyed with `ISDestroy()`, every entry of `dmlist` should be destroyed with `DMDestroy()`,
2196   and all of the arrays should be freed with `PetscFree()`.
2197 
2198   Developer Notes:
2199   The `dmlist` is for the inner subdomains or the outer subdomains or all subdomains?
2200 
2201   The names are inconsistent, the hooks use `DMSubDomainHook` which is nothing like `DMCreateDomainDecomposition()` while `DMRefineHook` is used for `DMRefine()`.
2202 
2203 .seealso: [](ch_dmbase), `DM`, `DMCreateFieldDecomposition()`, `DMDestroy()`, `DMCreateDomainDecompositionScatters()`, `DMView()`, `DMCreateInterpolation()`,
2204           `DMSubDomainHookAdd()`, `DMSubDomainHookRemove()`,`DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`
2205 @*/
2206 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *n, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
2207 {
2208   DMSubDomainHookLink link;
2209   PetscInt            i, l;
2210 
2211   PetscFunctionBegin;
2212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2213   if (n) {
2214     PetscAssertPointer(n, 2);
2215     *n = 0;
2216   }
2217   if (namelist) {
2218     PetscAssertPointer(namelist, 3);
2219     *namelist = NULL;
2220   }
2221   if (innerislist) {
2222     PetscAssertPointer(innerislist, 4);
2223     *innerislist = NULL;
2224   }
2225   if (outerislist) {
2226     PetscAssertPointer(outerislist, 5);
2227     *outerislist = NULL;
2228   }
2229   if (dmlist) {
2230     PetscAssertPointer(dmlist, 6);
2231     *dmlist = NULL;
2232   }
2233   /*
2234    Is it a good idea to apply the following check across all impls?
2235    Perhaps some impls can have a well-defined decomposition before DMSetUp?
2236    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
2237    */
2238   PetscCheck(dm->setupcalled, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
2239   if (dm->ops->createdomaindecomposition) {
2240     PetscUseTypeMethod(dm, createdomaindecomposition, &l, namelist, innerislist, outerislist, dmlist);
2241     /* copy subdomain hooks and context over to the subdomain DMs */
2242     if (dmlist && *dmlist) {
2243       for (i = 0; i < l; i++) {
2244         for (link = dm->subdomainhook; link; link = link->next) {
2245           if (link->ddhook) PetscCall((*link->ddhook)(dm, (*dmlist)[i], link->ctx));
2246         }
2247         if (dm->ctx) (*dmlist)[i]->ctx = dm->ctx;
2248       }
2249     }
2250     if (n) *n = l;
2251   }
2252   PetscFunctionReturn(PETSC_SUCCESS);
2253 }
2254 
2255 /*@C
2256   DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector for subdomains created with
2257   `DMCreateDomainDecomposition()`
2258 
2259   Not Collective
2260 
2261   Input Parameters:
2262 + dm     - the `DM` object
2263 . n      - the number of subdomains
2264 - subdms - the local subdomains
2265 
2266   Output Parameters:
2267 + iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
2268 . oscat - scatter from global vector to overlapping global vector entries on subdomain
2269 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
2270 
2271   Level: developer
2272 
2273   Note:
2274   This is an alternative to the iis and ois arguments in `DMCreateDomainDecomposition()` that allow for the solution
2275   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
2276   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
2277   solution and residual data.
2278 
2279   Developer Note:
2280   Can the subdms input be anything or are they exactly the `DM` obtained from
2281   `DMCreateDomainDecomposition()`?
2282 
2283 .seealso: [](ch_dmbase), `DM`, `DMCreateDomainDecomposition()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateFieldIS()`
2284 @*/
2285 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm, PetscInt n, DM *subdms, VecScatter *iscat[], VecScatter *oscat[], VecScatter *gscat[])
2286 {
2287   PetscFunctionBegin;
2288   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2289   PetscAssertPointer(subdms, 3);
2290   PetscUseTypeMethod(dm, createddscatters, n, subdms, iscat, oscat, gscat);
2291   PetscFunctionReturn(PETSC_SUCCESS);
2292 }
2293 
2294 /*@
2295   DMRefine - Refines a `DM` object using a standard nonadaptive refinement of the underlying mesh
2296 
2297   Collective
2298 
2299   Input Parameters:
2300 + dm   - the `DM` object
2301 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
2302 
2303   Output Parameter:
2304 . dmf - the refined `DM`, or `NULL`
2305 
2306   Options Database Key:
2307 . -dm_plex_cell_refiner <strategy> - chooses the refinement strategy, e.g. regular, tohex
2308 
2309   Level: developer
2310 
2311   Note:
2312   If no refinement was done, the return value is `NULL`
2313 
2314 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`,
2315           `DMRefineHookAdd()`, `DMRefineHookRemove()`
2316 @*/
2317 PetscErrorCode DMRefine(DM dm, MPI_Comm comm, DM *dmf)
2318 {
2319   DMRefineHookLink link;
2320 
2321   PetscFunctionBegin;
2322   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2323   PetscCall(PetscLogEventBegin(DM_Refine, dm, 0, 0, 0));
2324   PetscUseTypeMethod(dm, refine, comm, dmf);
2325   if (*dmf) {
2326     (*dmf)->ops->creatematrix = dm->ops->creatematrix;
2327 
2328     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmf));
2329 
2330     (*dmf)->ctx       = dm->ctx;
2331     (*dmf)->leveldown = dm->leveldown;
2332     (*dmf)->levelup   = dm->levelup + 1;
2333 
2334     PetscCall(DMSetMatType(*dmf, dm->mattype));
2335     for (link = dm->refinehook; link; link = link->next) {
2336       if (link->refinehook) PetscCall((*link->refinehook)(dm, *dmf, link->ctx));
2337     }
2338   }
2339   PetscCall(PetscLogEventEnd(DM_Refine, dm, 0, 0, 0));
2340   PetscFunctionReturn(PETSC_SUCCESS);
2341 }
2342 
2343 /*@C
2344   DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
2345 
2346   Logically Collective; No Fortran Support
2347 
2348   Input Parameters:
2349 + coarse     - `DM` on which to run a hook when interpolating to a finer level
2350 . refinehook - function to run when setting up the finer level
2351 . interphook - function to run to update data on finer levels (once per `SNESSolve()`)
2352 - ctx        - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2353 
2354   Calling sequence of `refinehook`:
2355 + coarse - coarse level `DM`
2356 . fine   - fine level `DM` to interpolate problem to
2357 - ctx    - optional user-defined function context
2358 
2359   Calling sequence of `interphook`:
2360 + coarse - coarse level `DM`
2361 . interp - matrix interpolating a coarse-level solution to the finer grid
2362 . fine   - fine level `DM` to update
2363 - ctx    - optional user-defined function context
2364 
2365   Level: advanced
2366 
2367   Notes:
2368   This function is only needed if auxiliary data that is attached to the `DM`s via, for example, `PetscObjectCompose()`, needs to be
2369   passed to fine grids while grid sequencing.
2370 
2371   The actual interpolation is done when `DMInterpolate()` is called.
2372 
2373   If this function is called multiple times, the hooks will be run in the order they are added.
2374 
2375 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2376 @*/
2377 PetscErrorCode DMRefineHookAdd(DM coarse, PetscErrorCode (*refinehook)(DM coarse, DM fine, void *ctx), PetscErrorCode (*interphook)(DM coarse, Mat interp, DM fine, void *ctx), void *ctx)
2378 {
2379   DMRefineHookLink link, *p;
2380 
2381   PetscFunctionBegin;
2382   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2383   for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
2384     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
2385   }
2386   PetscCall(PetscNew(&link));
2387   link->refinehook = refinehook;
2388   link->interphook = interphook;
2389   link->ctx        = ctx;
2390   link->next       = NULL;
2391   *p               = link;
2392   PetscFunctionReturn(PETSC_SUCCESS);
2393 }
2394 
2395 /*@C
2396   DMRefineHookRemove - remove a callback from the list of hooks, that have been set with `DMRefineHookAdd()`, to be run when interpolating
2397   a nonlinear problem to a finer grid
2398 
2399   Logically Collective; No Fortran Support
2400 
2401   Input Parameters:
2402 + coarse     - the `DM` on which to run a hook when restricting to a coarser level
2403 . refinehook - function to run when setting up a finer level
2404 . interphook - function to run to update data on finer levels
2405 - ctx        - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2406 
2407   Level: advanced
2408 
2409   Note:
2410   This function does nothing if the hook is not in the list.
2411 
2412 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `DMCoarsenHookRemove()`, `DMInterpolate()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2413 @*/
2414 PetscErrorCode DMRefineHookRemove(DM coarse, PetscErrorCode (*refinehook)(DM, DM, void *), PetscErrorCode (*interphook)(DM, Mat, DM, void *), void *ctx)
2415 {
2416   DMRefineHookLink link, *p;
2417 
2418   PetscFunctionBegin;
2419   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2420   for (p = &coarse->refinehook; *p; p = &(*p)->next) { /* Search the list of current hooks */
2421     if ((*p)->refinehook == refinehook && (*p)->interphook == interphook && (*p)->ctx == ctx) {
2422       link = *p;
2423       *p   = link->next;
2424       PetscCall(PetscFree(link));
2425       break;
2426     }
2427   }
2428   PetscFunctionReturn(PETSC_SUCCESS);
2429 }
2430 
2431 /*@
2432   DMInterpolate - interpolates user-defined problem data attached to a `DM` to a finer `DM` by running hooks registered by `DMRefineHookAdd()`
2433 
2434   Collective if any hooks are
2435 
2436   Input Parameters:
2437 + coarse - coarser `DM` to use as a base
2438 . interp - interpolation matrix, apply using `MatInterpolate()`
2439 - fine   - finer `DM` to update
2440 
2441   Level: developer
2442 
2443   Developer Note:
2444   This routine is called `DMInterpolate()` while the hook is called `DMRefineHookAdd()`. It would be better to have an
2445   an API with consistent terminology.
2446 
2447 .seealso: [](ch_dmbase), `DM`, `DMRefineHookAdd()`, `MatInterpolate()`
2448 @*/
2449 PetscErrorCode DMInterpolate(DM coarse, Mat interp, DM fine)
2450 {
2451   DMRefineHookLink link;
2452 
2453   PetscFunctionBegin;
2454   for (link = fine->refinehook; link; link = link->next) {
2455     if (link->interphook) PetscCall((*link->interphook)(coarse, interp, fine, link->ctx));
2456   }
2457   PetscFunctionReturn(PETSC_SUCCESS);
2458 }
2459 
2460 /*@
2461   DMInterpolateSolution - Interpolates a solution from a coarse mesh to a fine mesh.
2462 
2463   Collective
2464 
2465   Input Parameters:
2466 + coarse    - coarse `DM`
2467 . fine      - fine `DM`
2468 . interp    - (optional) the matrix computed by `DMCreateInterpolation()`.  Implementations may not need this, but if it
2469             is available it can avoid some recomputation.  If it is provided, `MatInterpolate()` will be used if
2470             the coarse `DM` does not have a specialized implementation.
2471 - coarseSol - solution on the coarse mesh
2472 
2473   Output Parameter:
2474 . fineSol - the interpolation of coarseSol to the fine mesh
2475 
2476   Level: developer
2477 
2478   Note:
2479   This function exists because the interpolation of a solution vector between meshes is not always a linear
2480   map.  For example, if a boundary value problem has an inhomogeneous Dirichlet boundary condition that is compressed
2481   out of the solution vector.  Or if interpolation is inherently a nonlinear operation, such as a method using
2482   slope-limiting reconstruction.
2483 
2484   Developer Note:
2485   This doesn't just interpolate "solutions" so its API name is questionable.
2486 
2487 .seealso: [](ch_dmbase), `DM`, `DMInterpolate()`, `DMCreateInterpolation()`
2488 @*/
2489 PetscErrorCode DMInterpolateSolution(DM coarse, DM fine, Mat interp, Vec coarseSol, Vec fineSol)
2490 {
2491   PetscErrorCode (*interpsol)(DM, DM, Mat, Vec, Vec) = NULL;
2492 
2493   PetscFunctionBegin;
2494   PetscValidHeaderSpecific(coarse, DM_CLASSID, 1);
2495   if (interp) PetscValidHeaderSpecific(interp, MAT_CLASSID, 3);
2496   PetscValidHeaderSpecific(coarseSol, VEC_CLASSID, 4);
2497   PetscValidHeaderSpecific(fineSol, VEC_CLASSID, 5);
2498 
2499   PetscCall(PetscObjectQueryFunction((PetscObject)coarse, "DMInterpolateSolution_C", &interpsol));
2500   if (interpsol) {
2501     PetscCall((*interpsol)(coarse, fine, interp, coarseSol, fineSol));
2502   } else if (interp) {
2503     PetscCall(MatInterpolate(interp, coarseSol, fineSol));
2504   } else SETERRQ(PetscObjectComm((PetscObject)coarse), PETSC_ERR_SUP, "DM %s does not implement DMInterpolateSolution()", ((PetscObject)coarse)->type_name);
2505   PetscFunctionReturn(PETSC_SUCCESS);
2506 }
2507 
2508 /*@
2509   DMGetRefineLevel - Gets the number of refinements that have generated this `DM` from some initial `DM`.
2510 
2511   Not Collective
2512 
2513   Input Parameter:
2514 . dm - the `DM` object
2515 
2516   Output Parameter:
2517 . level - number of refinements
2518 
2519   Level: developer
2520 
2521   Note:
2522   This can be used, by example, to set the number of coarser levels associated with this `DM` for a multigrid solver.
2523 
2524 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2525 @*/
2526 PetscErrorCode DMGetRefineLevel(DM dm, PetscInt *level)
2527 {
2528   PetscFunctionBegin;
2529   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2530   *level = dm->levelup;
2531   PetscFunctionReturn(PETSC_SUCCESS);
2532 }
2533 
2534 /*@
2535   DMSetRefineLevel - Sets the number of refinements that have generated this `DM`.
2536 
2537   Not Collective
2538 
2539   Input Parameters:
2540 + dm    - the `DM` object
2541 - level - number of refinements
2542 
2543   Level: advanced
2544 
2545   Notes:
2546   This value is used by `PCMG` to determine how many multigrid levels to use
2547 
2548   The values are usually set automatically by the process that is causing the refinements of an initial `DM` by calling this routine.
2549 
2550 .seealso: [](ch_dmbase), `DM`, `DMGetRefineLevel()`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
2551 @*/
2552 PetscErrorCode DMSetRefineLevel(DM dm, PetscInt level)
2553 {
2554   PetscFunctionBegin;
2555   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2556   dm->levelup = level;
2557   PetscFunctionReturn(PETSC_SUCCESS);
2558 }
2559 
2560 /*@
2561   DMExtrude - Extrude a `DM` object from a surface
2562 
2563   Collective
2564 
2565   Input Parameters:
2566 + dm     - the `DM` object
2567 - layers - the number of extruded cell layers
2568 
2569   Output Parameter:
2570 . dme - the extruded `DM`, or `NULL`
2571 
2572   Level: developer
2573 
2574   Note:
2575   If no extrusion was done, the return value is `NULL`
2576 
2577 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`
2578 @*/
2579 PetscErrorCode DMExtrude(DM dm, PetscInt layers, DM *dme)
2580 {
2581   PetscFunctionBegin;
2582   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2583   PetscUseTypeMethod(dm, extrude, layers, dme);
2584   if (*dme) {
2585     (*dme)->ops->creatematrix = dm->ops->creatematrix;
2586     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dme));
2587     (*dme)->ctx = dm->ctx;
2588     PetscCall(DMSetMatType(*dme, dm->mattype));
2589   }
2590   PetscFunctionReturn(PETSC_SUCCESS);
2591 }
2592 
2593 PetscErrorCode DMGetBasisTransformDM_Internal(DM dm, DM *tdm)
2594 {
2595   PetscFunctionBegin;
2596   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2597   PetscAssertPointer(tdm, 2);
2598   *tdm = dm->transformDM;
2599   PetscFunctionReturn(PETSC_SUCCESS);
2600 }
2601 
2602 PetscErrorCode DMGetBasisTransformVec_Internal(DM dm, Vec *tv)
2603 {
2604   PetscFunctionBegin;
2605   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2606   PetscAssertPointer(tv, 2);
2607   *tv = dm->transform;
2608   PetscFunctionReturn(PETSC_SUCCESS);
2609 }
2610 
2611 /*@
2612   DMHasBasisTransform - Whether the `DM` employs a basis transformation from functions in global vectors to functions in local vectors
2613 
2614   Input Parameter:
2615 . dm - The `DM`
2616 
2617   Output Parameter:
2618 . flg - `PETSC_TRUE` if a basis transformation should be done
2619 
2620   Level: developer
2621 
2622 .seealso: [](ch_dmbase), `DM`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()`, `DMPlexCreateBasisRotation()`
2623 @*/
2624 PetscErrorCode DMHasBasisTransform(DM dm, PetscBool *flg)
2625 {
2626   Vec tv;
2627 
2628   PetscFunctionBegin;
2629   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2630   PetscAssertPointer(flg, 2);
2631   PetscCall(DMGetBasisTransformVec_Internal(dm, &tv));
2632   *flg = tv ? PETSC_TRUE : PETSC_FALSE;
2633   PetscFunctionReturn(PETSC_SUCCESS);
2634 }
2635 
2636 PetscErrorCode DMConstructBasisTransform_Internal(DM dm)
2637 {
2638   PetscSection s, ts;
2639   PetscScalar *ta;
2640   PetscInt     cdim, pStart, pEnd, p, Nf, f, Nc, dof;
2641 
2642   PetscFunctionBegin;
2643   PetscCall(DMGetCoordinateDim(dm, &cdim));
2644   PetscCall(DMGetLocalSection(dm, &s));
2645   PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
2646   PetscCall(PetscSectionGetNumFields(s, &Nf));
2647   PetscCall(DMClone(dm, &dm->transformDM));
2648   PetscCall(DMGetLocalSection(dm->transformDM, &ts));
2649   PetscCall(PetscSectionSetNumFields(ts, Nf));
2650   PetscCall(PetscSectionSetChart(ts, pStart, pEnd));
2651   for (f = 0; f < Nf; ++f) {
2652     PetscCall(PetscSectionGetFieldComponents(s, f, &Nc));
2653     /* We could start to label fields by their transformation properties */
2654     if (Nc != cdim) continue;
2655     for (p = pStart; p < pEnd; ++p) {
2656       PetscCall(PetscSectionGetFieldDof(s, p, f, &dof));
2657       if (!dof) continue;
2658       PetscCall(PetscSectionSetFieldDof(ts, p, f, PetscSqr(cdim)));
2659       PetscCall(PetscSectionAddDof(ts, p, PetscSqr(cdim)));
2660     }
2661   }
2662   PetscCall(PetscSectionSetUp(ts));
2663   PetscCall(DMCreateLocalVector(dm->transformDM, &dm->transform));
2664   PetscCall(VecGetArray(dm->transform, &ta));
2665   for (p = pStart; p < pEnd; ++p) {
2666     for (f = 0; f < Nf; ++f) {
2667       PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof));
2668       if (dof) {
2669         PetscReal          x[3] = {0.0, 0.0, 0.0};
2670         PetscScalar       *tva;
2671         const PetscScalar *A;
2672 
2673         /* TODO Get quadrature point for this dual basis vector for coordinate */
2674         PetscCall((*dm->transformGetMatrix)(dm, x, PETSC_TRUE, &A, dm->transformCtx));
2675         PetscCall(DMPlexPointLocalFieldRef(dm->transformDM, p, f, ta, (void *)&tva));
2676         PetscCall(PetscArraycpy(tva, A, PetscSqr(cdim)));
2677       }
2678     }
2679   }
2680   PetscCall(VecRestoreArray(dm->transform, &ta));
2681   PetscFunctionReturn(PETSC_SUCCESS);
2682 }
2683 
2684 PetscErrorCode DMCopyTransform(DM dm, DM newdm)
2685 {
2686   PetscFunctionBegin;
2687   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2688   PetscValidHeaderSpecific(newdm, DM_CLASSID, 2);
2689   newdm->transformCtx       = dm->transformCtx;
2690   newdm->transformSetUp     = dm->transformSetUp;
2691   newdm->transformDestroy   = NULL;
2692   newdm->transformGetMatrix = dm->transformGetMatrix;
2693   if (newdm->transformSetUp) PetscCall(DMConstructBasisTransform_Internal(newdm));
2694   PetscFunctionReturn(PETSC_SUCCESS);
2695 }
2696 
2697 /*@C
2698   DMGlobalToLocalHookAdd - adds a callback to be run when `DMGlobalToLocal()` is called
2699 
2700   Logically Collective
2701 
2702   Input Parameters:
2703 + dm        - the `DM`
2704 . beginhook - function to run at the beginning of `DMGlobalToLocalBegin()`
2705 . endhook   - function to run after `DMGlobalToLocalEnd()` has completed
2706 - ctx       - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2707 
2708   Calling sequence of `beginhook`:
2709 + dm   - global `DM`
2710 . g    - global vector
2711 . mode - mode
2712 . l    - local vector
2713 - ctx  - optional user-defined function context
2714 
2715   Calling sequence of `endhook`:
2716 + dm   - global `DM`
2717 . g    - global vector
2718 . mode - mode
2719 . l    - local vector
2720 - ctx  - optional user-defined function context
2721 
2722   Level: advanced
2723 
2724   Note:
2725   The hook may be used to provide, for example, values that represent boundary conditions in the local vectors that do not exist on the global vector.
2726 
2727 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocal()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2728 @*/
2729 PetscErrorCode DMGlobalToLocalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM dm, Vec g, InsertMode mode, Vec l, void *ctx), PetscErrorCode (*endhook)(DM dm, Vec g, InsertMode mode, Vec l, void *ctx), void *ctx)
2730 {
2731   DMGlobalToLocalHookLink link, *p;
2732 
2733   PetscFunctionBegin;
2734   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2735   for (p = &dm->gtolhook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2736   PetscCall(PetscNew(&link));
2737   link->beginhook = beginhook;
2738   link->endhook   = endhook;
2739   link->ctx       = ctx;
2740   link->next      = NULL;
2741   *p              = link;
2742   PetscFunctionReturn(PETSC_SUCCESS);
2743 }
2744 
2745 static PetscErrorCode DMGlobalToLocalHook_Constraints(DM dm, Vec g, InsertMode mode, Vec l, void *ctx)
2746 {
2747   Mat          cMat;
2748   Vec          cVec, cBias;
2749   PetscSection section, cSec;
2750   PetscInt     pStart, pEnd, p, dof;
2751 
2752   PetscFunctionBegin;
2753   (void)g;
2754   (void)ctx;
2755   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2756   PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, &cBias));
2757   if (cMat && (mode == INSERT_VALUES || mode == INSERT_ALL_VALUES || mode == INSERT_BC_VALUES)) {
2758     PetscInt nRows;
2759 
2760     PetscCall(MatGetSize(cMat, &nRows, NULL));
2761     if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS);
2762     PetscCall(DMGetLocalSection(dm, &section));
2763     PetscCall(MatCreateVecs(cMat, NULL, &cVec));
2764     PetscCall(MatMult(cMat, l, cVec));
2765     if (cBias) PetscCall(VecAXPY(cVec, 1., cBias));
2766     PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
2767     for (p = pStart; p < pEnd; p++) {
2768       PetscCall(PetscSectionGetDof(cSec, p, &dof));
2769       if (dof) {
2770         PetscScalar *vals;
2771         PetscCall(VecGetValuesSection(cVec, cSec, p, &vals));
2772         PetscCall(VecSetValuesSection(l, section, p, vals, INSERT_ALL_VALUES));
2773       }
2774     }
2775     PetscCall(VecDestroy(&cVec));
2776   }
2777   PetscFunctionReturn(PETSC_SUCCESS);
2778 }
2779 
2780 /*@
2781   DMGlobalToLocal - update local vectors from global vector
2782 
2783   Neighbor-wise Collective
2784 
2785   Input Parameters:
2786 + dm   - the `DM` object
2787 . g    - the global vector
2788 . mode - `INSERT_VALUES` or `ADD_VALUES`
2789 - l    - the local vector
2790 
2791   Level: beginner
2792 
2793   Notes:
2794   The communication involved in this update can be overlapped with computation by instead using
2795   `DMGlobalToLocalBegin()` and `DMGlobalToLocalEnd()`.
2796 
2797   `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2798 
2799 .seealso: [](ch_dmbase), `DM`, `DMGlobalToLocalHookAdd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`,
2800           `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`,
2801           `DMGlobalToLocalBegin()` `DMGlobalToLocalEnd()`
2802 @*/
2803 PetscErrorCode DMGlobalToLocal(DM dm, Vec g, InsertMode mode, Vec l)
2804 {
2805   PetscFunctionBegin;
2806   PetscCall(DMGlobalToLocalBegin(dm, g, mode, l));
2807   PetscCall(DMGlobalToLocalEnd(dm, g, mode, l));
2808   PetscFunctionReturn(PETSC_SUCCESS);
2809 }
2810 
2811 /*@
2812   DMGlobalToLocalBegin - Begins updating local vectors from global vector
2813 
2814   Neighbor-wise Collective
2815 
2816   Input Parameters:
2817 + dm   - the `DM` object
2818 . g    - the global vector
2819 . mode - `INSERT_VALUES` or `ADD_VALUES`
2820 - l    - the local vector
2821 
2822   Level: intermediate
2823 
2824   Notes:
2825   The operation is completed with `DMGlobalToLocalEnd()`
2826 
2827   One can perform local computations between the `DMGlobalToLocalBegin()` and  `DMGlobalToLocalEnd()` to overlap communication and computation
2828 
2829   `DMGlobalToLocal()` is a short form of  `DMGlobalToLocalBegin()` and  `DMGlobalToLocalEnd()`
2830 
2831   `DMGlobalToLocalHookAdd()` may be used to provide additional operations that are performed during the update process.
2832 
2833 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`
2834 @*/
2835 PetscErrorCode DMGlobalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
2836 {
2837   PetscSF                 sf;
2838   DMGlobalToLocalHookLink link;
2839 
2840   PetscFunctionBegin;
2841   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2842   for (link = dm->gtolhook; link; link = link->next) {
2843     if (link->beginhook) PetscCall((*link->beginhook)(dm, g, mode, l, link->ctx));
2844   }
2845   PetscCall(DMGetSectionSF(dm, &sf));
2846   if (sf) {
2847     const PetscScalar *gArray;
2848     PetscScalar       *lArray;
2849     PetscMemType       lmtype, gmtype;
2850 
2851     PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode);
2852     PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype));
2853     PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype));
2854     PetscCall(PetscSFBcastWithMemTypeBegin(sf, MPIU_SCALAR, gmtype, gArray, lmtype, lArray, MPI_REPLACE));
2855     PetscCall(VecRestoreArrayAndMemType(l, &lArray));
2856     PetscCall(VecRestoreArrayReadAndMemType(g, &gArray));
2857   } else {
2858     PetscUseTypeMethod(dm, globaltolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2859   }
2860   PetscFunctionReturn(PETSC_SUCCESS);
2861 }
2862 
2863 /*@
2864   DMGlobalToLocalEnd - Ends updating local vectors from global vector
2865 
2866   Neighbor-wise Collective
2867 
2868   Input Parameters:
2869 + dm   - the `DM` object
2870 . g    - the global vector
2871 . mode - `INSERT_VALUES` or `ADD_VALUES`
2872 - l    - the local vector
2873 
2874   Level: intermediate
2875 
2876   Note:
2877   See `DMGlobalToLocalBegin()` for details.
2878 
2879 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMLocalToGlobalBegin()`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`
2880 @*/
2881 PetscErrorCode DMGlobalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
2882 {
2883   PetscSF                 sf;
2884   const PetscScalar      *gArray;
2885   PetscScalar            *lArray;
2886   PetscBool               transform;
2887   DMGlobalToLocalHookLink link;
2888   PetscMemType            lmtype, gmtype;
2889 
2890   PetscFunctionBegin;
2891   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2892   PetscCall(DMGetSectionSF(dm, &sf));
2893   PetscCall(DMHasBasisTransform(dm, &transform));
2894   if (sf) {
2895     PetscCheck(mode != ADD_VALUES, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", (int)mode);
2896 
2897     PetscCall(VecGetArrayAndMemType(l, &lArray, &lmtype));
2898     PetscCall(VecGetArrayReadAndMemType(g, &gArray, &gmtype));
2899     PetscCall(PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray, MPI_REPLACE));
2900     PetscCall(VecRestoreArrayAndMemType(l, &lArray));
2901     PetscCall(VecRestoreArrayReadAndMemType(g, &gArray));
2902     if (transform) PetscCall(DMPlexGlobalToLocalBasis(dm, l));
2903   } else {
2904     PetscUseTypeMethod(dm, globaltolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
2905   }
2906   PetscCall(DMGlobalToLocalHook_Constraints(dm, g, mode, l, NULL));
2907   for (link = dm->gtolhook; link; link = link->next) {
2908     if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx));
2909   }
2910   PetscFunctionReturn(PETSC_SUCCESS);
2911 }
2912 
2913 /*@C
2914   DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
2915 
2916   Logically Collective
2917 
2918   Input Parameters:
2919 + dm        - the `DM`
2920 . beginhook - function to run at the beginning of `DMLocalToGlobalBegin()`
2921 . endhook   - function to run after `DMLocalToGlobalEnd()` has completed
2922 - ctx       - [optional] user-defined context for provide data for the hooks (may be `NULL`)
2923 
2924   Calling sequence of `beginhook`:
2925 + global - global `DM`
2926 . l      - local vector
2927 . mode   - mode
2928 . g      - global vector
2929 - ctx    - optional user-defined function context
2930 
2931   Calling sequence of `endhook`:
2932 + global - global `DM`
2933 . l      - local vector
2934 . mode   - mode
2935 . g      - global vector
2936 - ctx    - optional user-defined function context
2937 
2938   Level: advanced
2939 
2940 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMRefineHookAdd()`, `DMGlobalToLocalHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
2941 @*/
2942 PetscErrorCode DMLocalToGlobalHookAdd(DM dm, PetscErrorCode (*beginhook)(DM global, Vec l, InsertMode mode, Vec g, void *ctx), PetscErrorCode (*endhook)(DM global, Vec l, InsertMode mode, Vec g, void *ctx), void *ctx)
2943 {
2944   DMLocalToGlobalHookLink link, *p;
2945 
2946   PetscFunctionBegin;
2947   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2948   for (p = &dm->ltoghook; *p; p = &(*p)->next) { } /* Scan to the end of the current list of hooks */
2949   PetscCall(PetscNew(&link));
2950   link->beginhook = beginhook;
2951   link->endhook   = endhook;
2952   link->ctx       = ctx;
2953   link->next      = NULL;
2954   *p              = link;
2955   PetscFunctionReturn(PETSC_SUCCESS);
2956 }
2957 
2958 static PetscErrorCode DMLocalToGlobalHook_Constraints(DM dm, Vec l, InsertMode mode, Vec g, void *ctx)
2959 {
2960   PetscFunctionBegin;
2961   (void)g;
2962   (void)ctx;
2963   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2964   if (mode == ADD_VALUES || mode == ADD_ALL_VALUES || mode == ADD_BC_VALUES) {
2965     Mat          cMat;
2966     Vec          cVec;
2967     PetscInt     nRows;
2968     PetscSection section, cSec;
2969     PetscInt     pStart, pEnd, p, dof;
2970 
2971     PetscCall(DMGetDefaultConstraints(dm, &cSec, &cMat, NULL));
2972     if (!cMat) PetscFunctionReturn(PETSC_SUCCESS);
2973 
2974     PetscCall(MatGetSize(cMat, &nRows, NULL));
2975     if (nRows <= 0) PetscFunctionReturn(PETSC_SUCCESS);
2976     PetscCall(DMGetLocalSection(dm, &section));
2977     PetscCall(MatCreateVecs(cMat, NULL, &cVec));
2978     PetscCall(PetscSectionGetChart(cSec, &pStart, &pEnd));
2979     for (p = pStart; p < pEnd; p++) {
2980       PetscCall(PetscSectionGetDof(cSec, p, &dof));
2981       if (dof) {
2982         PetscInt     d;
2983         PetscScalar *vals;
2984         PetscCall(VecGetValuesSection(l, section, p, &vals));
2985         PetscCall(VecSetValuesSection(cVec, cSec, p, vals, mode));
2986         /* for this to be the true transpose, we have to zero the values that
2987          * we just extracted */
2988         for (d = 0; d < dof; d++) vals[d] = 0.;
2989       }
2990     }
2991     PetscCall(MatMultTransposeAdd(cMat, cVec, l, l));
2992     PetscCall(VecDestroy(&cVec));
2993   }
2994   PetscFunctionReturn(PETSC_SUCCESS);
2995 }
2996 /*@
2997   DMLocalToGlobal - updates global vectors from local vectors
2998 
2999   Neighbor-wise Collective
3000 
3001   Input Parameters:
3002 + dm   - the `DM` object
3003 . l    - the local vector
3004 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point.
3005 - g    - the global vector
3006 
3007   Level: beginner
3008 
3009   Notes:
3010   The communication involved in this update can be overlapped with computation by using
3011   `DMLocalToGlobalBegin()` and `DMLocalToGlobalEnd()`.
3012 
3013   In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
3014 
3015   `INSERT_VALUES` is not supported for `DMDA`; in that case simply compute the values directly into a global vector instead of a local one.
3016 
3017   Use `DMLocalToGlobalHookAdd()` to add additional operations that are performed on the data during the update process
3018 
3019 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`, `DMLocalToGlobalHookAdd()`, `DMGlobaToLocallHookAdd()`
3020 @*/
3021 PetscErrorCode DMLocalToGlobal(DM dm, Vec l, InsertMode mode, Vec g)
3022 {
3023   PetscFunctionBegin;
3024   PetscCall(DMLocalToGlobalBegin(dm, l, mode, g));
3025   PetscCall(DMLocalToGlobalEnd(dm, l, mode, g));
3026   PetscFunctionReturn(PETSC_SUCCESS);
3027 }
3028 
3029 /*@
3030   DMLocalToGlobalBegin - begins updating global vectors from local vectors
3031 
3032   Neighbor-wise Collective
3033 
3034   Input Parameters:
3035 + dm   - the `DM` object
3036 . l    - the local vector
3037 . mode - if `INSERT_VALUES` then no parallel communication is used, if `ADD_VALUES` then all ghost points from the same base point accumulate into that base point.
3038 - g    - the global vector
3039 
3040   Level: intermediate
3041 
3042   Notes:
3043   In the `ADD_VALUES` case you normally would zero the receiving vector before beginning this operation.
3044 
3045   `INSERT_VALUES is` not supported for `DMDA`, in that case simply compute the values directly into a global vector instead of a local one.
3046 
3047   Use `DMLocalToGlobalEnd()` to complete the communication process.
3048 
3049   `DMLocalToGlobal()` is a short form of  `DMLocalToGlobalBegin()` and  `DMLocalToGlobalEnd()`
3050 
3051   `DMLocalToGlobalHookAdd()` may be used to provide additional operations that are performed during the update process.
3052 
3053 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobal()`, `DMLocalToGlobalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocal()`, `DMGlobalToLocalEnd()`, `DMGlobalToLocalBegin()`
3054 @*/
3055 PetscErrorCode DMLocalToGlobalBegin(DM dm, Vec l, InsertMode mode, Vec g)
3056 {
3057   PetscSF                 sf;
3058   PetscSection            s, gs;
3059   DMLocalToGlobalHookLink link;
3060   Vec                     tmpl;
3061   const PetscScalar      *lArray;
3062   PetscScalar            *gArray;
3063   PetscBool               isInsert, transform, l_inplace = PETSC_FALSE, g_inplace = PETSC_FALSE;
3064   PetscMemType            lmtype = PETSC_MEMTYPE_HOST, gmtype = PETSC_MEMTYPE_HOST;
3065 
3066   PetscFunctionBegin;
3067   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3068   for (link = dm->ltoghook; link; link = link->next) {
3069     if (link->beginhook) PetscCall((*link->beginhook)(dm, l, mode, g, link->ctx));
3070   }
3071   PetscCall(DMLocalToGlobalHook_Constraints(dm, l, mode, g, NULL));
3072   PetscCall(DMGetSectionSF(dm, &sf));
3073   PetscCall(DMGetLocalSection(dm, &s));
3074   switch (mode) {
3075   case INSERT_VALUES:
3076   case INSERT_ALL_VALUES:
3077   case INSERT_BC_VALUES:
3078     isInsert = PETSC_TRUE;
3079     break;
3080   case ADD_VALUES:
3081   case ADD_ALL_VALUES:
3082   case ADD_BC_VALUES:
3083     isInsert = PETSC_FALSE;
3084     break;
3085   default:
3086     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3087   }
3088   if ((sf && !isInsert) || (s && isInsert)) {
3089     PetscCall(DMHasBasisTransform(dm, &transform));
3090     if (transform) {
3091       PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3092       PetscCall(VecCopy(l, tmpl));
3093       PetscCall(DMPlexLocalToGlobalBasis(dm, tmpl));
3094       PetscCall(VecGetArrayRead(tmpl, &lArray));
3095     } else if (isInsert) {
3096       PetscCall(VecGetArrayRead(l, &lArray));
3097     } else {
3098       PetscCall(VecGetArrayReadAndMemType(l, &lArray, &lmtype));
3099       l_inplace = PETSC_TRUE;
3100     }
3101     if (s && isInsert) {
3102       PetscCall(VecGetArray(g, &gArray));
3103     } else {
3104       PetscCall(VecGetArrayAndMemType(g, &gArray, &gmtype));
3105       g_inplace = PETSC_TRUE;
3106     }
3107     if (sf && !isInsert) {
3108       PetscCall(PetscSFReduceWithMemTypeBegin(sf, MPIU_SCALAR, lmtype, lArray, gmtype, gArray, MPIU_SUM));
3109     } else if (s && isInsert) {
3110       PetscInt gStart, pStart, pEnd, p;
3111 
3112       PetscCall(DMGetGlobalSection(dm, &gs));
3113       PetscCall(PetscSectionGetChart(s, &pStart, &pEnd));
3114       PetscCall(VecGetOwnershipRange(g, &gStart, NULL));
3115       for (p = pStart; p < pEnd; ++p) {
3116         PetscInt dof, gdof, cdof, gcdof, off, goff, d, e;
3117 
3118         PetscCall(PetscSectionGetDof(s, p, &dof));
3119         PetscCall(PetscSectionGetDof(gs, p, &gdof));
3120         PetscCall(PetscSectionGetConstraintDof(s, p, &cdof));
3121         PetscCall(PetscSectionGetConstraintDof(gs, p, &gcdof));
3122         PetscCall(PetscSectionGetOffset(s, p, &off));
3123         PetscCall(PetscSectionGetOffset(gs, p, &goff));
3124         /* Ignore off-process data and points with no global data */
3125         if (!gdof || goff < 0) continue;
3126         PetscCheck(dof == gdof, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3127         /* If no constraints are enforced in the global vector */
3128         if (!gcdof) {
3129           for (d = 0; d < dof; ++d) gArray[goff - gStart + d] = lArray[off + d];
3130           /* If constraints are enforced in the global vector */
3131         } else if (cdof == gcdof) {
3132           const PetscInt *cdofs;
3133           PetscInt        cind = 0;
3134 
3135           PetscCall(PetscSectionGetConstraintIndices(s, p, &cdofs));
3136           for (d = 0, e = 0; d < dof; ++d) {
3137             if ((cind < cdof) && (d == cdofs[cind])) {
3138               ++cind;
3139               continue;
3140             }
3141             gArray[goff - gStart + e++] = lArray[off + d];
3142           }
3143         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Inconsistent sizes, p: %" PetscInt_FMT " dof: %" PetscInt_FMT " gdof: %" PetscInt_FMT " cdof: %" PetscInt_FMT " gcdof: %" PetscInt_FMT, p, dof, gdof, cdof, gcdof);
3144       }
3145     }
3146     if (g_inplace) {
3147       PetscCall(VecRestoreArrayAndMemType(g, &gArray));
3148     } else {
3149       PetscCall(VecRestoreArray(g, &gArray));
3150     }
3151     if (transform) {
3152       PetscCall(VecRestoreArrayRead(tmpl, &lArray));
3153       PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3154     } else if (l_inplace) {
3155       PetscCall(VecRestoreArrayReadAndMemType(l, &lArray));
3156     } else {
3157       PetscCall(VecRestoreArrayRead(l, &lArray));
3158     }
3159   } else {
3160     PetscUseTypeMethod(dm, localtoglobalbegin, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3161   }
3162   PetscFunctionReturn(PETSC_SUCCESS);
3163 }
3164 
3165 /*@
3166   DMLocalToGlobalEnd - updates global vectors from local vectors
3167 
3168   Neighbor-wise Collective
3169 
3170   Input Parameters:
3171 + dm   - the `DM` object
3172 . l    - the local vector
3173 . mode - `INSERT_VALUES` or `ADD_VALUES`
3174 - g    - the global vector
3175 
3176   Level: intermediate
3177 
3178   Note:
3179   See `DMLocalToGlobalBegin()` for full details
3180 
3181 .seealso: [](ch_dmbase), `DM`, `DMLocalToGlobalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`
3182 @*/
3183 PetscErrorCode DMLocalToGlobalEnd(DM dm, Vec l, InsertMode mode, Vec g)
3184 {
3185   PetscSF                 sf;
3186   PetscSection            s;
3187   DMLocalToGlobalHookLink link;
3188   PetscBool               isInsert, transform;
3189 
3190   PetscFunctionBegin;
3191   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3192   PetscCall(DMGetSectionSF(dm, &sf));
3193   PetscCall(DMGetLocalSection(dm, &s));
3194   switch (mode) {
3195   case INSERT_VALUES:
3196   case INSERT_ALL_VALUES:
3197     isInsert = PETSC_TRUE;
3198     break;
3199   case ADD_VALUES:
3200   case ADD_ALL_VALUES:
3201     isInsert = PETSC_FALSE;
3202     break;
3203   default:
3204     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %d", mode);
3205   }
3206   if (sf && !isInsert) {
3207     const PetscScalar *lArray;
3208     PetscScalar       *gArray;
3209     Vec                tmpl;
3210 
3211     PetscCall(DMHasBasisTransform(dm, &transform));
3212     if (transform) {
3213       PetscCall(DMGetNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3214       PetscCall(VecGetArrayRead(tmpl, &lArray));
3215     } else {
3216       PetscCall(VecGetArrayReadAndMemType(l, &lArray, NULL));
3217     }
3218     PetscCall(VecGetArrayAndMemType(g, &gArray, NULL));
3219     PetscCall(PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_SUM));
3220     if (transform) {
3221       PetscCall(VecRestoreArrayRead(tmpl, &lArray));
3222       PetscCall(DMRestoreNamedLocalVector(dm, "__petsc_dm_transform_local_copy", &tmpl));
3223     } else {
3224       PetscCall(VecRestoreArrayReadAndMemType(l, &lArray));
3225     }
3226     PetscCall(VecRestoreArrayAndMemType(g, &gArray));
3227   } else if (s && isInsert) {
3228   } else {
3229     PetscUseTypeMethod(dm, localtoglobalend, l, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), g);
3230   }
3231   for (link = dm->ltoghook; link; link = link->next) {
3232     if (link->endhook) PetscCall((*link->endhook)(dm, g, mode, l, link->ctx));
3233   }
3234   PetscFunctionReturn(PETSC_SUCCESS);
3235 }
3236 
3237 /*@
3238   DMLocalToLocalBegin - Begins the process of mapping values from a local vector (that include
3239   ghost points that contain irrelevant values) to another local vector where the ghost points
3240   in the second are set correctly from values on other MPI ranks.
3241 
3242   Neighbor-wise Collective
3243 
3244   Input Parameters:
3245 + dm   - the `DM` object
3246 . g    - the original local vector
3247 - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3248 
3249   Output Parameter:
3250 . l - the local vector with correct ghost values
3251 
3252   Level: intermediate
3253 
3254   Note:
3255   Must be followed by `DMLocalToLocalEnd()`.
3256 
3257 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalEnd()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3258 @*/
3259 PetscErrorCode DMLocalToLocalBegin(DM dm, Vec g, InsertMode mode, Vec l)
3260 {
3261   PetscFunctionBegin;
3262   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3263   PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3264   PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3265   PetscUseTypeMethod(dm, localtolocalbegin, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3266   PetscFunctionReturn(PETSC_SUCCESS);
3267 }
3268 
3269 /*@
3270   DMLocalToLocalEnd - Maps from a local vector to another local vector where the ghost
3271   points in the second are set correctly. Must be preceded by `DMLocalToLocalBegin()`.
3272 
3273   Neighbor-wise Collective
3274 
3275   Input Parameters:
3276 + dm   - the `DM` object
3277 . g    - the original local vector
3278 - mode - one of `INSERT_VALUES` or `ADD_VALUES`
3279 
3280   Output Parameter:
3281 . l - the local vector with correct ghost values
3282 
3283   Level: intermediate
3284 
3285 .seealso: [](ch_dmbase), `DM`, `DMLocalToLocalBegin()`, `DMCoarsen()`, `DMDestroy()`, `DMView()`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMGlobalToLocalEnd()`, `DMLocalToGlobalBegin()`
3286 @*/
3287 PetscErrorCode DMLocalToLocalEnd(DM dm, Vec g, InsertMode mode, Vec l)
3288 {
3289   PetscFunctionBegin;
3290   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3291   PetscValidHeaderSpecific(g, VEC_CLASSID, 2);
3292   PetscValidHeaderSpecific(l, VEC_CLASSID, 4);
3293   PetscUseTypeMethod(dm, localtolocalend, g, mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode), l);
3294   PetscFunctionReturn(PETSC_SUCCESS);
3295 }
3296 
3297 /*@
3298   DMCoarsen - Coarsens a `DM` object using a standard, non-adaptive coarsening of the underlying mesh
3299 
3300   Collective
3301 
3302   Input Parameters:
3303 + dm   - the `DM` object
3304 - comm - the communicator to contain the new `DM` object (or `MPI_COMM_NULL`)
3305 
3306   Output Parameter:
3307 . dmc - the coarsened `DM`
3308 
3309   Level: developer
3310 
3311 .seealso: [](ch_dmbase), `DM`, `DMRefine()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateDomainDecomposition()`,
3312           `DMCoarsenHookAdd()`, `DMCoarsenHookRemove()`
3313 @*/
3314 PetscErrorCode DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
3315 {
3316   DMCoarsenHookLink link;
3317 
3318   PetscFunctionBegin;
3319   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3320   PetscCall(PetscLogEventBegin(DM_Coarsen, dm, 0, 0, 0));
3321   PetscUseTypeMethod(dm, coarsen, comm, dmc);
3322   if (*dmc) {
3323     (*dmc)->bind_below = dm->bind_below; /* Propagate this from parent DM; otherwise -dm_bind_below will be useless for multigrid cases. */
3324     PetscCall(DMSetCoarseDM(dm, *dmc));
3325     (*dmc)->ops->creatematrix = dm->ops->creatematrix;
3326     PetscCall(PetscObjectCopyFortranFunctionPointers((PetscObject)dm, (PetscObject)*dmc));
3327     (*dmc)->ctx       = dm->ctx;
3328     (*dmc)->levelup   = dm->levelup;
3329     (*dmc)->leveldown = dm->leveldown + 1;
3330     PetscCall(DMSetMatType(*dmc, dm->mattype));
3331     for (link = dm->coarsenhook; link; link = link->next) {
3332       if (link->coarsenhook) PetscCall((*link->coarsenhook)(dm, *dmc, link->ctx));
3333     }
3334   }
3335   PetscCall(PetscLogEventEnd(DM_Coarsen, dm, 0, 0, 0));
3336   PetscCheck(*dmc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "NULL coarse mesh produced");
3337   PetscFunctionReturn(PETSC_SUCCESS);
3338 }
3339 
3340 /*@C
3341   DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
3342 
3343   Logically Collective; No Fortran Support
3344 
3345   Input Parameters:
3346 + fine         - `DM` on which to run a hook when restricting to a coarser level
3347 . coarsenhook  - function to run when setting up a coarser level
3348 . restricthook - function to run to update data on coarser levels (called once per `SNESSolve()`)
3349 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3350 
3351   Calling sequence of `coarsenhook`:
3352 + fine   - fine level `DM`
3353 . coarse - coarse level `DM` to restrict problem to
3354 - ctx    - optional user-defined function context
3355 
3356   Calling sequence of `restricthook`:
3357 + fine      - fine level `DM`
3358 . mrestrict - matrix restricting a fine-level solution to the coarse grid, usually the transpose of the interpolation
3359 . rscale    - scaling vector for restriction
3360 . inject    - matrix restricting by injection
3361 . coarse    - coarse level DM to update
3362 - ctx       - optional user-defined function context
3363 
3364   Level: advanced
3365 
3366   Notes:
3367   This function is only needed if auxiliary data, attached to the `DM` with `PetscObjectCompose()`, needs to be set up or passed from the fine `DM` to the coarse `DM`.
3368 
3369   If this function is called multiple times, the hooks will be run in the order they are added.
3370 
3371   In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3372   extract the finest level information from its context (instead of from the `SNES`).
3373 
3374   The hooks are automatically called by `DMRestrict()`
3375 
3376 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3377 @*/
3378 PetscErrorCode DMCoarsenHookAdd(DM fine, PetscErrorCode (*coarsenhook)(DM fine, DM coarse, void *ctx), PetscErrorCode (*restricthook)(DM fine, Mat mrestrict, Vec rscale, Mat inject, DM coarse, void *ctx), void *ctx)
3379 {
3380   DMCoarsenHookLink link, *p;
3381 
3382   PetscFunctionBegin;
3383   PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3384   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3385     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
3386   }
3387   PetscCall(PetscNew(&link));
3388   link->coarsenhook  = coarsenhook;
3389   link->restricthook = restricthook;
3390   link->ctx          = ctx;
3391   link->next         = NULL;
3392   *p                 = link;
3393   PetscFunctionReturn(PETSC_SUCCESS);
3394 }
3395 
3396 /*@C
3397   DMCoarsenHookRemove - remove a callback set with `DMCoarsenHookAdd()`
3398 
3399   Logically Collective; No Fortran Support
3400 
3401   Input Parameters:
3402 + fine         - `DM` on which to run a hook when restricting to a coarser level
3403 . coarsenhook  - function to run when setting up a coarser level
3404 . restricthook - function to run to update data on coarser levels
3405 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3406 
3407   Level: advanced
3408 
3409   Notes:
3410   This function does nothing if the `coarsenhook` is not in the list.
3411 
3412   See `DMCoarsenHookAdd()` for the calling sequence of `coarsenhook` and `restricthook`
3413 
3414 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`
3415 @*/
3416 PetscErrorCode DMCoarsenHookRemove(DM fine, PetscErrorCode (*coarsenhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, Mat, Vec, Mat, DM, void *), void *ctx)
3417 {
3418   DMCoarsenHookLink link, *p;
3419 
3420   PetscFunctionBegin;
3421   PetscValidHeaderSpecific(fine, DM_CLASSID, 1);
3422   for (p = &fine->coarsenhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3423     if ((*p)->coarsenhook == coarsenhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3424       link = *p;
3425       *p   = link->next;
3426       PetscCall(PetscFree(link));
3427       break;
3428     }
3429   }
3430   PetscFunctionReturn(PETSC_SUCCESS);
3431 }
3432 
3433 /*@
3434   DMRestrict - restricts user-defined problem data to a coarser `DM` by running hooks registered by `DMCoarsenHookAdd()`
3435 
3436   Collective if any hooks are
3437 
3438   Input Parameters:
3439 + fine    - finer `DM` from which the data is obtained
3440 . restrct - restriction matrix, apply using `MatRestrict()`, usually the transpose of the interpolation
3441 . rscale  - scaling vector for restriction
3442 . inject  - injection matrix, also use `MatRestrict()`
3443 - coarse  - coarser `DM` to update
3444 
3445   Level: developer
3446 
3447   Developer Note:
3448   Though this routine is called `DMRestrict()` the hooks are added with `DMCoarsenHookAdd()`, a consistent terminology would be better
3449 
3450 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMInterpolate()`, `DMRefineHookAdd()`
3451 @*/
3452 PetscErrorCode DMRestrict(DM fine, Mat restrct, Vec rscale, Mat inject, DM coarse)
3453 {
3454   DMCoarsenHookLink link;
3455 
3456   PetscFunctionBegin;
3457   for (link = fine->coarsenhook; link; link = link->next) {
3458     if (link->restricthook) PetscCall((*link->restricthook)(fine, restrct, rscale, inject, coarse, link->ctx));
3459   }
3460   PetscFunctionReturn(PETSC_SUCCESS);
3461 }
3462 
3463 /*@C
3464   DMSubDomainHookAdd - adds a callback to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()`
3465 
3466   Logically Collective; No Fortran Support
3467 
3468   Input Parameters:
3469 + global       - global `DM`
3470 . ddhook       - function to run to pass data to the decomposition `DM` upon its creation
3471 . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3472 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3473 
3474   Calling sequence of `ddhook`:
3475 + global - global `DM`
3476 . block  - subdomain `DM`
3477 - ctx    - optional user-defined function context
3478 
3479   Calling sequence of `restricthook`:
3480 + global - global `DM`
3481 . out    - scatter to the outer (with ghost and overlap points) sub vector
3482 . in     - scatter to sub vector values only owned locally
3483 . block  - subdomain `DM`
3484 - ctx    - optional user-defined function context
3485 
3486   Level: advanced
3487 
3488   Notes:
3489   This function can be used if auxiliary data needs to be set up on subdomain `DM`s.
3490 
3491   If this function is called multiple times, the hooks will be run in the order they are added.
3492 
3493   In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
3494   extract the global information from its context (instead of from the `SNES`).
3495 
3496   Developer Note:
3497   It is unclear what "block solve" means within the definition of `restricthook`
3498 
3499 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookRemove()`, `DMRefineHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`, `DMCreateDomainDecomposition()`
3500 @*/
3501 PetscErrorCode DMSubDomainHookAdd(DM global, PetscErrorCode (*ddhook)(DM global, DM block, void *ctx), PetscErrorCode (*restricthook)(DM global, VecScatter out, VecScatter in, DM block, void *ctx), void *ctx)
3502 {
3503   DMSubDomainHookLink link, *p;
3504 
3505   PetscFunctionBegin;
3506   PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3507   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Scan to the end of the current list of hooks */
3508     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) PetscFunctionReturn(PETSC_SUCCESS);
3509   }
3510   PetscCall(PetscNew(&link));
3511   link->restricthook = restricthook;
3512   link->ddhook       = ddhook;
3513   link->ctx          = ctx;
3514   link->next         = NULL;
3515   *p                 = link;
3516   PetscFunctionReturn(PETSC_SUCCESS);
3517 }
3518 
3519 /*@C
3520   DMSubDomainHookRemove - remove a callback from the list to be run when restricting a problem to subdomain `DM`s with `DMCreateDomainDecomposition()`
3521 
3522   Logically Collective; No Fortran Support
3523 
3524   Input Parameters:
3525 + global       - global `DM`
3526 . ddhook       - function to run to pass data to the decomposition `DM` upon its creation
3527 . restricthook - function to run to update data on block solve (at the beginning of the block solve)
3528 - ctx          - [optional] user-defined context for provide data for the hooks (may be `NULL`)
3529 
3530   Level: advanced
3531 
3532   Note:
3533   See `DMSubDomainHookAdd()` for the calling sequences of `ddhook` and `restricthook`
3534 
3535 .seealso: [](ch_dmbase), `DM`, `DMSubDomainHookAdd()`, `SNESFASGetInterpolation()`, `SNESFASGetInjection()`, `PetscObjectCompose()`, `PetscContainerCreate()`,
3536           `DMCreateDomainDecomposition()`
3537 @*/
3538 PetscErrorCode DMSubDomainHookRemove(DM global, PetscErrorCode (*ddhook)(DM, DM, void *), PetscErrorCode (*restricthook)(DM, VecScatter, VecScatter, DM, void *), void *ctx)
3539 {
3540   DMSubDomainHookLink link, *p;
3541 
3542   PetscFunctionBegin;
3543   PetscValidHeaderSpecific(global, DM_CLASSID, 1);
3544   for (p = &global->subdomainhook; *p; p = &(*p)->next) { /* Search the list of current hooks */
3545     if ((*p)->ddhook == ddhook && (*p)->restricthook == restricthook && (*p)->ctx == ctx) {
3546       link = *p;
3547       *p   = link->next;
3548       PetscCall(PetscFree(link));
3549       break;
3550     }
3551   }
3552   PetscFunctionReturn(PETSC_SUCCESS);
3553 }
3554 
3555 /*@
3556   DMSubDomainRestrict - restricts user-defined problem data to a subdomain `DM` by running hooks registered by `DMSubDomainHookAdd()`
3557 
3558   Collective if any hooks are
3559 
3560   Input Parameters:
3561 + global   - The global `DM` to use as a base
3562 . oscatter - The scatter from domain global vector filling subdomain global vector with overlap
3563 . gscatter - The scatter from domain global vector filling subdomain local vector with ghosts
3564 - subdm    - The subdomain `DM` to update
3565 
3566   Level: developer
3567 
3568 .seealso: [](ch_dmbase), `DM`, `DMCoarsenHookAdd()`, `MatRestrict()`, `DMCreateDomainDecomposition()`
3569 @*/
3570 PetscErrorCode DMSubDomainRestrict(DM global, VecScatter oscatter, VecScatter gscatter, DM subdm)
3571 {
3572   DMSubDomainHookLink link;
3573 
3574   PetscFunctionBegin;
3575   for (link = global->subdomainhook; link; link = link->next) {
3576     if (link->restricthook) PetscCall((*link->restricthook)(global, oscatter, gscatter, subdm, link->ctx));
3577   }
3578   PetscFunctionReturn(PETSC_SUCCESS);
3579 }
3580 
3581 /*@
3582   DMGetCoarsenLevel - Gets the number of coarsenings that have generated this `DM`.
3583 
3584   Not Collective
3585 
3586   Input Parameter:
3587 . dm - the `DM` object
3588 
3589   Output Parameter:
3590 . level - number of coarsenings
3591 
3592   Level: developer
3593 
3594 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMSetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3595 @*/
3596 PetscErrorCode DMGetCoarsenLevel(DM dm, PetscInt *level)
3597 {
3598   PetscFunctionBegin;
3599   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3600   PetscAssertPointer(level, 2);
3601   *level = dm->leveldown;
3602   PetscFunctionReturn(PETSC_SUCCESS);
3603 }
3604 
3605 /*@
3606   DMSetCoarsenLevel - Sets the number of coarsenings that have generated this `DM`.
3607 
3608   Collective
3609 
3610   Input Parameters:
3611 + dm    - the `DM` object
3612 - level - number of coarsenings
3613 
3614   Level: developer
3615 
3616   Note:
3617   This is rarely used directly, the information is automatically set when a `DM` is created with `DMCoarsen()`
3618 
3619 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMGetCoarsenLevel()`, `DMGetRefineLevel()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3620 @*/
3621 PetscErrorCode DMSetCoarsenLevel(DM dm, PetscInt level)
3622 {
3623   PetscFunctionBegin;
3624   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3625   dm->leveldown = level;
3626   PetscFunctionReturn(PETSC_SUCCESS);
3627 }
3628 
3629 /*@
3630   DMRefineHierarchy - Refines a `DM` object, all levels at once
3631 
3632   Collective
3633 
3634   Input Parameters:
3635 + dm      - the `DM` object
3636 - nlevels - the number of levels of refinement
3637 
3638   Output Parameter:
3639 . dmf - the refined `DM` hierarchy
3640 
3641   Level: developer
3642 
3643 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMCoarsenHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3644 @*/
3645 PetscErrorCode DMRefineHierarchy(DM dm, PetscInt nlevels, DM dmf[])
3646 {
3647   PetscFunctionBegin;
3648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3649   PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3650   if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS);
3651   PetscAssertPointer(dmf, 3);
3652   if (dm->ops->refine && !dm->ops->refinehierarchy) {
3653     PetscInt i;
3654 
3655     PetscCall(DMRefine(dm, PetscObjectComm((PetscObject)dm), &dmf[0]));
3656     for (i = 1; i < nlevels; i++) PetscCall(DMRefine(dmf[i - 1], PetscObjectComm((PetscObject)dm), &dmf[i]));
3657   } else PetscUseTypeMethod(dm, refinehierarchy, nlevels, dmf);
3658   PetscFunctionReturn(PETSC_SUCCESS);
3659 }
3660 
3661 /*@
3662   DMCoarsenHierarchy - Coarsens a `DM` object, all levels at once
3663 
3664   Collective
3665 
3666   Input Parameters:
3667 + dm      - the `DM` object
3668 - nlevels - the number of levels of coarsening
3669 
3670   Output Parameter:
3671 . dmc - the coarsened `DM` hierarchy
3672 
3673   Level: developer
3674 
3675 .seealso: [](ch_dmbase), `DM`, `DMCoarsen()`, `DMRefineHierarchy()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`
3676 @*/
3677 PetscErrorCode DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
3678 {
3679   PetscFunctionBegin;
3680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3681   PetscCheck(nlevels >= 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "nlevels cannot be negative");
3682   if (nlevels == 0) PetscFunctionReturn(PETSC_SUCCESS);
3683   PetscAssertPointer(dmc, 3);
3684   if (dm->ops->coarsen && !dm->ops->coarsenhierarchy) {
3685     PetscInt i;
3686 
3687     PetscCall(DMCoarsen(dm, PetscObjectComm((PetscObject)dm), &dmc[0]));
3688     for (i = 1; i < nlevels; i++) PetscCall(DMCoarsen(dmc[i - 1], PetscObjectComm((PetscObject)dm), &dmc[i]));
3689   } else PetscUseTypeMethod(dm, coarsenhierarchy, nlevels, dmc);
3690   PetscFunctionReturn(PETSC_SUCCESS);
3691 }
3692 
3693 /*@C
3694   DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the `DM` is destroyed
3695 
3696   Logically Collective if the function is collective
3697 
3698   Input Parameters:
3699 + dm      - the `DM` object
3700 - destroy - the destroy function, see `PetscCtxDestroyFn` for the calling sequence
3701 
3702   Level: intermediate
3703 
3704 .seealso: [](ch_dmbase), `DM`, `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`,
3705           `DMGetApplicationContext()`, `PetscCtxDestroyFn`
3706 @*/
3707 PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscCtxDestroyFn *destroy)
3708 {
3709   PetscFunctionBegin;
3710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3711   dm->ctxdestroy = destroy;
3712   PetscFunctionReturn(PETSC_SUCCESS);
3713 }
3714 
3715 /*@
3716   DMSetApplicationContext - Set a user context into a `DM` object
3717 
3718   Not Collective
3719 
3720   Input Parameters:
3721 + dm  - the `DM` object
3722 - ctx - the user context
3723 
3724   Level: intermediate
3725 
3726   Notes:
3727   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3728   In a multilevel solver, the user context is shared by all the `DM` in the hierarchy; it is thus not advisable
3729   to store objects that represent discretized quantities inside the context.
3730 
3731 .seealso: [](ch_dmbase), `DM`, `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3732 @*/
3733 PetscErrorCode DMSetApplicationContext(DM dm, void *ctx)
3734 {
3735   PetscFunctionBegin;
3736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3737   dm->ctx = ctx;
3738   PetscFunctionReturn(PETSC_SUCCESS);
3739 }
3740 
3741 /*@
3742   DMGetApplicationContext - Gets a user context from a `DM` object
3743 
3744   Not Collective
3745 
3746   Input Parameter:
3747 . dm - the `DM` object
3748 
3749   Output Parameter:
3750 . ctx - the user context
3751 
3752   Level: intermediate
3753 
3754   Note:
3755   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3756 
3757 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3758 @*/
3759 PetscErrorCode DMGetApplicationContext(DM dm, void *ctx)
3760 {
3761   PetscFunctionBegin;
3762   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3763   *(void **)ctx = dm->ctx;
3764   PetscFunctionReturn(PETSC_SUCCESS);
3765 }
3766 
3767 /*@C
3768   DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`.
3769 
3770   Logically Collective
3771 
3772   Input Parameters:
3773 + dm - the DM object
3774 - f  - the function that computes variable bounds used by SNESVI (use `NULL` to cancel a previous function that was set)
3775 
3776   Level: intermediate
3777 
3778 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3779          `DMSetJacobian()`
3780 @*/
3781 PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3782 {
3783   PetscFunctionBegin;
3784   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3785   dm->ops->computevariablebounds = f;
3786   PetscFunctionReturn(PETSC_SUCCESS);
3787 }
3788 
3789 /*@
3790   DMHasVariableBounds - does the `DM` object have a variable bounds function?
3791 
3792   Not Collective
3793 
3794   Input Parameter:
3795 . dm - the `DM` object to destroy
3796 
3797   Output Parameter:
3798 . flg - `PETSC_TRUE` if the variable bounds function exists
3799 
3800   Level: developer
3801 
3802 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3803 @*/
3804 PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3805 {
3806   PetscFunctionBegin;
3807   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3808   PetscAssertPointer(flg, 2);
3809   *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3810   PetscFunctionReturn(PETSC_SUCCESS);
3811 }
3812 
3813 /*@
3814   DMComputeVariableBounds - compute variable bounds used by `SNESVI`.
3815 
3816   Logically Collective
3817 
3818   Input Parameter:
3819 . dm - the `DM` object
3820 
3821   Output Parameters:
3822 + xl - lower bound
3823 - xu - upper bound
3824 
3825   Level: advanced
3826 
3827   Note:
3828   This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3829 
3830 .seealso: [](ch_dmbase), `DM`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3831 @*/
3832 PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3833 {
3834   PetscFunctionBegin;
3835   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3836   PetscValidHeaderSpecific(xl, VEC_CLASSID, 2);
3837   PetscValidHeaderSpecific(xu, VEC_CLASSID, 3);
3838   PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3839   PetscFunctionReturn(PETSC_SUCCESS);
3840 }
3841 
3842 /*@
3843   DMHasColoring - does the `DM` object have a method of providing a coloring?
3844 
3845   Not Collective
3846 
3847   Input Parameter:
3848 . dm - the DM object
3849 
3850   Output Parameter:
3851 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.
3852 
3853   Level: developer
3854 
3855 .seealso: [](ch_dmbase), `DM`, `DMCreateColoring()`
3856 @*/
3857 PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3858 {
3859   PetscFunctionBegin;
3860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3861   PetscAssertPointer(flg, 2);
3862   *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3863   PetscFunctionReturn(PETSC_SUCCESS);
3864 }
3865 
3866 /*@
3867   DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?
3868 
3869   Not Collective
3870 
3871   Input Parameter:
3872 . dm - the `DM` object
3873 
3874   Output Parameter:
3875 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.
3876 
3877   Level: developer
3878 
3879 .seealso: [](ch_dmbase), `DM`, `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3880 @*/
3881 PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3882 {
3883   PetscFunctionBegin;
3884   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3885   PetscAssertPointer(flg, 2);
3886   *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3887   PetscFunctionReturn(PETSC_SUCCESS);
3888 }
3889 
3890 /*@
3891   DMHasCreateInjection - does the `DM` object have a method of providing an injection?
3892 
3893   Not Collective
3894 
3895   Input Parameter:
3896 . dm - the `DM` object
3897 
3898   Output Parameter:
3899 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.
3900 
3901   Level: developer
3902 
3903 .seealso: [](ch_dmbase), `DM`, `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3904 @*/
3905 PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3906 {
3907   PetscFunctionBegin;
3908   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3909   PetscAssertPointer(flg, 2);
3910   if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3911   else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3912   PetscFunctionReturn(PETSC_SUCCESS);
3913 }
3914 
3915 PetscFunctionList DMList              = NULL;
3916 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
3917 
3918 /*@
3919   DMSetType - Builds a `DM`, for a particular `DM` implementation.
3920 
3921   Collective
3922 
3923   Input Parameters:
3924 + dm     - The `DM` object
3925 - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`
3926 
3927   Options Database Key:
3928 . -dm_type <type> - Sets the `DM` type; use -help for a list of available types
3929 
3930   Level: intermediate
3931 
3932   Note:
3933   Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPlexCreateBoxMesh()`
3934 
3935 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
3936 @*/
3937 PetscErrorCode DMSetType(DM dm, DMType method)
3938 {
3939   PetscErrorCode (*r)(DM);
3940   PetscBool match;
3941 
3942   PetscFunctionBegin;
3943   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3944   PetscCall(PetscObjectTypeCompare((PetscObject)dm, method, &match));
3945   if (match) PetscFunctionReturn(PETSC_SUCCESS);
3946 
3947   PetscCall(DMRegisterAll());
3948   PetscCall(PetscFunctionListFind(DMList, method, &r));
3949   PetscCheck(r, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3950 
3951   PetscTryTypeMethod(dm, destroy);
3952   PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));
3953   PetscCall(PetscObjectChangeTypeName((PetscObject)dm, method));
3954   PetscCall((*r)(dm));
3955   PetscFunctionReturn(PETSC_SUCCESS);
3956 }
3957 
3958 /*@
3959   DMGetType - Gets the `DM` type name (as a string) from the `DM`.
3960 
3961   Not Collective
3962 
3963   Input Parameter:
3964 . dm - The `DM`
3965 
3966   Output Parameter:
3967 . type - The `DMType` name
3968 
3969   Level: intermediate
3970 
3971 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
3972 @*/
3973 PetscErrorCode DMGetType(DM dm, DMType *type)
3974 {
3975   PetscFunctionBegin;
3976   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3977   PetscAssertPointer(type, 2);
3978   PetscCall(DMRegisterAll());
3979   *type = ((PetscObject)dm)->type_name;
3980   PetscFunctionReturn(PETSC_SUCCESS);
3981 }
3982 
3983 /*@
3984   DMConvert - Converts a `DM` to another `DM`, either of the same or different type.
3985 
3986   Collective
3987 
3988   Input Parameters:
3989 + dm      - the `DM`
3990 - newtype - new `DM` type (use "same" for the same type)
3991 
3992   Output Parameter:
3993 . M - pointer to new `DM`
3994 
3995   Level: intermediate
3996 
3997   Note:
3998   Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
3999   the MPI communicator of the generated `DM` is always the same as the communicator
4000   of the input `DM`.
4001 
4002 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
4003 @*/
4004 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
4005 {
4006   DM        B;
4007   char      convname[256];
4008   PetscBool sametype /*, issame */;
4009 
4010   PetscFunctionBegin;
4011   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4012   PetscValidType(dm, 1);
4013   PetscAssertPointer(M, 3);
4014   PetscCall(PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype));
4015   /* PetscCall(PetscStrcmp(newtype, "same", &issame)); */
4016   if (sametype) {
4017     *M = dm;
4018     PetscCall(PetscObjectReference((PetscObject)dm));
4019     PetscFunctionReturn(PETSC_SUCCESS);
4020   } else {
4021     PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;
4022 
4023     /*
4024        Order of precedence:
4025        1) See if a specialized converter is known to the current DM.
4026        2) See if a specialized converter is known to the desired DM class.
4027        3) See if a good general converter is registered for the desired class
4028        4) See if a good general converter is known for the current matrix.
4029        5) Use a really basic converter.
4030     */
4031 
4032     /* 1) See if a specialized converter is known to the current DM and the desired class */
4033     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4034     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4035     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4036     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4037     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4038     PetscCall(PetscObjectQueryFunction((PetscObject)dm, convname, &conv));
4039     if (conv) goto foundconv;
4040 
4041     /* 2)  See if a specialized converter is known to the desired DM class. */
4042     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &B));
4043     PetscCall(DMSetType(B, newtype));
4044     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4045     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4046     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4047     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4048     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4049     PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4050     if (conv) {
4051       PetscCall(DMDestroy(&B));
4052       goto foundconv;
4053     }
4054 
4055 #if 0
4056     /* 3) See if a good general converter is registered for the desired class */
4057     conv = B->ops->convertfrom;
4058     PetscCall(DMDestroy(&B));
4059     if (conv) goto foundconv;
4060 
4061     /* 4) See if a good general converter is known for the current matrix */
4062     if (dm->ops->convert) {
4063       conv = dm->ops->convert;
4064     }
4065     if (conv) goto foundconv;
4066 #endif
4067 
4068     /* 5) Use a really basic converter. */
4069     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
4070 
4071   foundconv:
4072     PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0));
4073     PetscCall((*conv)(dm, newtype, M));
4074     /* Things that are independent of DM type: We should consult DMClone() here */
4075     {
4076       const PetscReal *maxCell, *Lstart, *L;
4077 
4078       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
4079       PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L));
4080       (*M)->prealloc_only = dm->prealloc_only;
4081       PetscCall(PetscFree((*M)->vectype));
4082       PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype));
4083       PetscCall(PetscFree((*M)->mattype));
4084       PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype));
4085     }
4086     PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0));
4087   }
4088   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4089   PetscFunctionReturn(PETSC_SUCCESS);
4090 }
4091 
4092 /*--------------------------------------------------------------------------------------------------------------------*/
4093 
4094 /*@C
4095   DMRegister -  Adds a new `DM` type implementation
4096 
4097   Not Collective, No Fortran Support
4098 
4099   Input Parameters:
4100 + sname    - The name of a new user-defined creation routine
4101 - function - The creation routine itself
4102 
4103   Level: advanced
4104 
4105   Note:
4106   `DMRegister()` may be called multiple times to add several user-defined `DM`s
4107 
4108   Example Usage:
4109 .vb
4110     DMRegister("my_da", MyDMCreate);
4111 .ve
4112 
4113   Then, your `DM` type can be chosen with the procedural interface via
4114 .vb
4115     DMCreate(MPI_Comm, DM *);
4116     DMSetType(DM,"my_da");
4117 .ve
4118   or at runtime via the option
4119 .vb
4120     -da_type my_da
4121 .ve
4122 
4123 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
4124 @*/
4125 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
4126 {
4127   PetscFunctionBegin;
4128   PetscCall(DMInitializePackage());
4129   PetscCall(PetscFunctionListAdd(&DMList, sname, function));
4130   PetscFunctionReturn(PETSC_SUCCESS);
4131 }
4132 
4133 /*@
4134   DMLoad - Loads a DM that has been stored in binary  with `DMView()`.
4135 
4136   Collective
4137 
4138   Input Parameters:
4139 + newdm  - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4140            some related function before a call to `DMLoad()`.
4141 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4142            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
4143 
4144   Level: intermediate
4145 
4146   Notes:
4147   The type is determined by the data in the file, any type set into the DM before this call is ignored.
4148 
4149   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
4150   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
4151   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
4152 
4153 .seealso: [](ch_dmbase), `DM`, `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4154 @*/
4155 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4156 {
4157   PetscBool isbinary, ishdf5;
4158 
4159   PetscFunctionBegin;
4160   PetscValidHeaderSpecific(newdm, DM_CLASSID, 1);
4161   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4162   PetscCall(PetscViewerCheckReadable(viewer));
4163   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4164   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4165   PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0));
4166   if (isbinary) {
4167     PetscInt classid;
4168     char     type[256];
4169 
4170     PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
4171     PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %" PetscInt_FMT, classid);
4172     PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
4173     PetscCall(DMSetType(newdm, type));
4174     PetscTryTypeMethod(newdm, load, viewer);
4175   } else if (ishdf5) {
4176     PetscTryTypeMethod(newdm, load, viewer);
4177   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4178   PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0));
4179   PetscFunctionReturn(PETSC_SUCCESS);
4180 }
4181 
4182 /* FEM Support */
4183 
4184 PetscErrorCode DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt x[])
4185 {
4186   PetscInt f;
4187 
4188   PetscFunctionBegin;
4189   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4190   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %" PetscInt_FMT " |\n", x[f]));
4191   PetscFunctionReturn(PETSC_SUCCESS);
4192 }
4193 
4194 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4195 {
4196   PetscInt f;
4197 
4198   PetscFunctionBegin;
4199   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4200   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f])));
4201   PetscFunctionReturn(PETSC_SUCCESS);
4202 }
4203 
4204 PetscErrorCode DMPrintCellVectorReal(PetscInt c, const char name[], PetscInt len, const PetscReal x[])
4205 {
4206   PetscInt f;
4207 
4208   PetscFunctionBegin;
4209   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4210   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)x[f]));
4211   PetscFunctionReturn(PETSC_SUCCESS);
4212 }
4213 
4214 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4215 {
4216   PetscInt f, g;
4217 
4218   PetscFunctionBegin;
4219   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4220   for (f = 0; f < rows; ++f) {
4221     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  |"));
4222     for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4223     PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4224   }
4225   PetscFunctionReturn(PETSC_SUCCESS);
4226 }
4227 
4228 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4229 {
4230   PetscInt           localSize, bs;
4231   PetscMPIInt        size;
4232   Vec                x, xglob;
4233   const PetscScalar *xarray;
4234 
4235   PetscFunctionBegin;
4236   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4237   PetscCall(VecDuplicate(X, &x));
4238   PetscCall(VecCopy(X, x));
4239   PetscCall(VecFilter(x, tol));
4240   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4241   if (size > 1) {
4242     PetscCall(VecGetLocalSize(x, &localSize));
4243     PetscCall(VecGetArrayRead(x, &xarray));
4244     PetscCall(VecGetBlockSize(x, &bs));
4245     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4246   } else {
4247     xglob = x;
4248   }
4249   PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4250   if (size > 1) {
4251     PetscCall(VecDestroy(&xglob));
4252     PetscCall(VecRestoreArrayRead(x, &xarray));
4253   }
4254   PetscCall(VecDestroy(&x));
4255   PetscFunctionReturn(PETSC_SUCCESS);
4256 }
4257 
4258 /*@
4259   DMGetSection - Get the `PetscSection` encoding the local data layout for the `DM`.   This is equivalent to `DMGetLocalSection()`. Deprecated in v3.12
4260 
4261   Input Parameter:
4262 . dm - The `DM`
4263 
4264   Output Parameter:
4265 . section - The `PetscSection`
4266 
4267   Options Database Key:
4268 . -dm_petscsection_view - View the `PetscSection` created by the `DM`
4269 
4270   Level: advanced
4271 
4272   Notes:
4273   Use `DMGetLocalSection()` in new code.
4274 
4275   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4276 
4277 .seealso: [](ch_dmbase), `DM`, `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4278 @*/
4279 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4280 {
4281   PetscFunctionBegin;
4282   PetscCall(DMGetLocalSection(dm, section));
4283   PetscFunctionReturn(PETSC_SUCCESS);
4284 }
4285 
4286 /*@
4287   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4288 
4289   Input Parameter:
4290 . dm - The `DM`
4291 
4292   Output Parameter:
4293 . section - The `PetscSection`
4294 
4295   Options Database Key:
4296 . -dm_petscsection_view - View the section created by the `DM`
4297 
4298   Level: intermediate
4299 
4300   Note:
4301   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4302 
4303 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4304 @*/
4305 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4306 {
4307   PetscFunctionBegin;
4308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4309   PetscAssertPointer(section, 2);
4310   if (!dm->localSection && dm->ops->createlocalsection) {
4311     PetscInt d;
4312 
4313     if (dm->setfromoptionscalled) {
4314       PetscObject       obj = (PetscObject)dm;
4315       PetscViewer       viewer;
4316       PetscViewerFormat format;
4317       PetscBool         flg;
4318 
4319       PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4320       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4321       for (d = 0; d < dm->Nds; ++d) {
4322         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4323         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4324       }
4325       if (flg) {
4326         PetscCall(PetscViewerFlush(viewer));
4327         PetscCall(PetscViewerPopFormat(viewer));
4328         PetscCall(PetscViewerDestroy(&viewer));
4329       }
4330     }
4331     PetscUseTypeMethod(dm, createlocalsection);
4332     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4333   }
4334   *section = dm->localSection;
4335   PetscFunctionReturn(PETSC_SUCCESS);
4336 }
4337 
4338 /*@
4339   DMSetSection - Set the `PetscSection` encoding the local data layout for the `DM`.  This is equivalent to `DMSetLocalSection()`. Deprecated in v3.12
4340 
4341   Input Parameters:
4342 + dm      - The `DM`
4343 - section - The `PetscSection`
4344 
4345   Level: advanced
4346 
4347   Notes:
4348   Use `DMSetLocalSection()` in new code.
4349 
4350   Any existing `PetscSection` will be destroyed
4351 
4352 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4353 @*/
4354 PetscErrorCode DMSetSection(DM dm, PetscSection section)
4355 {
4356   PetscFunctionBegin;
4357   PetscCall(DMSetLocalSection(dm, section));
4358   PetscFunctionReturn(PETSC_SUCCESS);
4359 }
4360 
4361 /*@
4362   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4363 
4364   Input Parameters:
4365 + dm      - The `DM`
4366 - section - The `PetscSection`
4367 
4368   Level: intermediate
4369 
4370   Note:
4371   Any existing Section will be destroyed
4372 
4373 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4374 @*/
4375 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4376 {
4377   PetscInt numFields = 0;
4378   PetscInt f;
4379 
4380   PetscFunctionBegin;
4381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4382   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4383   PetscCall(PetscObjectReference((PetscObject)section));
4384   PetscCall(PetscSectionDestroy(&dm->localSection));
4385   dm->localSection = section;
4386   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4387   if (numFields) {
4388     PetscCall(DMSetNumFields(dm, numFields));
4389     for (f = 0; f < numFields; ++f) {
4390       PetscObject disc;
4391       const char *name;
4392 
4393       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4394       PetscCall(DMGetField(dm, f, NULL, &disc));
4395       PetscCall(PetscObjectSetName(disc, name));
4396     }
4397   }
4398   /* The global section and the SectionSF will be rebuilt
4399      in the next call to DMGetGlobalSection() and DMGetSectionSF(). */
4400   PetscCall(PetscSectionDestroy(&dm->globalSection));
4401   PetscCall(PetscSFDestroy(&dm->sectionSF));
4402   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4403 
4404   /* Clear scratch vectors */
4405   PetscCall(DMClearGlobalVectors(dm));
4406   PetscCall(DMClearLocalVectors(dm));
4407   PetscCall(DMClearNamedGlobalVectors(dm));
4408   PetscCall(DMClearNamedLocalVectors(dm));
4409   PetscFunctionReturn(PETSC_SUCCESS);
4410 }
4411 
4412 /*@C
4413   DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure.
4414 
4415   Input Parameter:
4416 . dm - The `DM`
4417 
4418   Output Parameters:
4419 + perm        - A permutation of the mesh points in the chart
4420 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking
4421 
4422   Level: developer
4423 
4424 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4425 @*/
4426 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts)
4427 {
4428   PetscFunctionBegin;
4429   *perm        = NULL;
4430   *blockStarts = NULL;
4431   PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts);
4432   PetscFunctionReturn(PETSC_SUCCESS);
4433 }
4434 
4435 /*@
4436   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4437 
4438   not Collective
4439 
4440   Input Parameter:
4441 . dm - The `DM`
4442 
4443   Output Parameters:
4444 + section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Returns `NULL` if there are no local constraints.
4445 . mat     - The `Mat` that interpolates local constraints: its width should be the layout size of the default section.  Returns `NULL` if there are no local constraints.
4446 - bias    - Vector containing bias to be added to constrained dofs
4447 
4448   Level: advanced
4449 
4450   Note:
4451   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4452 
4453 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4454 @*/
4455 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4456 {
4457   PetscFunctionBegin;
4458   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4459   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4460   if (section) *section = dm->defaultConstraint.section;
4461   if (mat) *mat = dm->defaultConstraint.mat;
4462   if (bias) *bias = dm->defaultConstraint.bias;
4463   PetscFunctionReturn(PETSC_SUCCESS);
4464 }
4465 
4466 /*@
4467   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4468 
4469   Collective
4470 
4471   Input Parameters:
4472 + dm      - The `DM`
4473 . section - The `PetscSection` describing the range of the constraint matrix: relates rows of the constraint matrix to dofs of the default section.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4474 . mat     - The `Mat` that interpolates local constraints: its width should be the layout size of the default section:  `NULL` indicates no constraints.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4475 - bias    - A bias vector to be added to constrained values in the local vector.  `NULL` indicates no bias.  Must have a local communicator (`PETSC_COMM_SELF` or derivative).
4476 
4477   Level: advanced
4478 
4479   Notes:
4480   If a constraint matrix is specified, then it is applied during `DMGlobalToLocalEnd()` when mode is `INSERT_VALUES`, `INSERT_BC_VALUES`, or `INSERT_ALL_VALUES`.  Without a constraint matrix, the local vector l returned by `DMGlobalToLocalEnd()` contains values that have been scattered from a global vector without modification; with a constraint matrix A, l is modified by computing c = A * l + bias, l[s[i]] = c[i], where the scatter s is defined by the `PetscSection` returned by `DMGetDefaultConstraints()`.
4481 
4482   If a constraint matrix is specified, then its adjoint is applied during `DMLocalToGlobalBegin()` when mode is `ADD_VALUES`, `ADD_BC_VALUES`, or `ADD_ALL_VALUES`.  Without a constraint matrix, the local vector l is accumulated into a global vector without modification; with a constraint matrix A, l is first modified by computing c[i] = l[s[i]], l[s[i]] = 0, l = l + A'*c, which is the adjoint of the operation described above.  Any bias, if specified, is ignored when accumulating.
4483 
4484   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4485 
4486 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4487 @*/
4488 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4489 {
4490   PetscMPIInt result;
4491 
4492   PetscFunctionBegin;
4493   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4494   if (section) {
4495     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4496     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4497     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4498   }
4499   if (mat) {
4500     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4501     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4502     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4503   }
4504   if (bias) {
4505     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4506     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4507     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4508   }
4509   PetscCall(PetscObjectReference((PetscObject)section));
4510   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4511   dm->defaultConstraint.section = section;
4512   PetscCall(PetscObjectReference((PetscObject)mat));
4513   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4514   dm->defaultConstraint.mat = mat;
4515   PetscCall(PetscObjectReference((PetscObject)bias));
4516   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4517   dm->defaultConstraint.bias = bias;
4518   PetscFunctionReturn(PETSC_SUCCESS);
4519 }
4520 
4521 #if defined(PETSC_USE_DEBUG)
4522 /*
4523   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4524 
4525   Input Parameters:
4526 + dm - The `DM`
4527 . localSection - `PetscSection` describing the local data layout
4528 - globalSection - `PetscSection` describing the global data layout
4529 
4530   Level: intermediate
4531 
4532 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4533 */
4534 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4535 {
4536   MPI_Comm        comm;
4537   PetscLayout     layout;
4538   const PetscInt *ranges;
4539   PetscInt        pStart, pEnd, p, nroots;
4540   PetscMPIInt     size, rank;
4541   PetscBool       valid = PETSC_TRUE, gvalid;
4542 
4543   PetscFunctionBegin;
4544   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4545   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4546   PetscCallMPI(MPI_Comm_size(comm, &size));
4547   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4548   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4549   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4550   PetscCall(PetscLayoutCreate(comm, &layout));
4551   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4552   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4553   PetscCall(PetscLayoutSetUp(layout));
4554   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4555   for (p = pStart; p < pEnd; ++p) {
4556     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4557 
4558     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4559     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4560     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4561     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4562     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4563     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4564     if (!gdof) continue; /* Censored point */
4565     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4566       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4567       valid = PETSC_FALSE;
4568     }
4569     if (gcdof && (gcdof != cdof)) {
4570       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4571       valid = PETSC_FALSE;
4572     }
4573     if (gdof < 0) {
4574       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4575       for (d = 0; d < gsize; ++d) {
4576         PetscInt offset = -(goff + 1) + d, r;
4577 
4578         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4579         if (r < 0) r = -(r + 2);
4580         if ((r < 0) || (r >= size)) {
4581           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4582           valid = PETSC_FALSE;
4583           break;
4584         }
4585       }
4586     }
4587   }
4588   PetscCall(PetscLayoutDestroy(&layout));
4589   PetscCall(PetscSynchronizedFlush(comm, NULL));
4590   PetscCallMPI(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm));
4591   if (!gvalid) {
4592     PetscCall(DMView(dm, NULL));
4593     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4594   }
4595   PetscFunctionReturn(PETSC_SUCCESS);
4596 }
4597 #endif
4598 
4599 static PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4600 {
4601   PetscErrorCode (*f)(DM, PetscSF *);
4602 
4603   PetscFunctionBegin;
4604   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4605   PetscAssertPointer(sf, 2);
4606   PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4607   if (f) PetscCall(f(dm, sf));
4608   else *sf = dm->sf;
4609   PetscFunctionReturn(PETSC_SUCCESS);
4610 }
4611 
4612 /*@
4613   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4614 
4615   Collective
4616 
4617   Input Parameter:
4618 . dm - The `DM`
4619 
4620   Output Parameter:
4621 . section - The `PetscSection`
4622 
4623   Level: intermediate
4624 
4625   Note:
4626   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4627 
4628 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4629 @*/
4630 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4631 {
4632   PetscFunctionBegin;
4633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4634   PetscAssertPointer(section, 2);
4635   if (!dm->globalSection) {
4636     PetscSection s;
4637     PetscSF      sf;
4638 
4639     PetscCall(DMGetLocalSection(dm, &s));
4640     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4641     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4642     PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4643     PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4644     PetscCall(PetscLayoutDestroy(&dm->map));
4645     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4646     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4647   }
4648   *section = dm->globalSection;
4649   PetscFunctionReturn(PETSC_SUCCESS);
4650 }
4651 
4652 /*@
4653   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4654 
4655   Input Parameters:
4656 + dm      - The `DM`
4657 - section - The PetscSection, or `NULL`
4658 
4659   Level: intermediate
4660 
4661   Note:
4662   Any existing `PetscSection` will be destroyed
4663 
4664 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4665 @*/
4666 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4667 {
4668   PetscFunctionBegin;
4669   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4670   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4671   PetscCall(PetscObjectReference((PetscObject)section));
4672   PetscCall(PetscSectionDestroy(&dm->globalSection));
4673   dm->globalSection = section;
4674 #if defined(PETSC_USE_DEBUG)
4675   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4676 #endif
4677   /* Clear global scratch vectors and sectionSF */
4678   PetscCall(PetscSFDestroy(&dm->sectionSF));
4679   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4680   PetscCall(DMClearGlobalVectors(dm));
4681   PetscCall(DMClearNamedGlobalVectors(dm));
4682   PetscFunctionReturn(PETSC_SUCCESS);
4683 }
4684 
4685 /*@
4686   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4687   it is created from the default `PetscSection` layouts in the `DM`.
4688 
4689   Input Parameter:
4690 . dm - The `DM`
4691 
4692   Output Parameter:
4693 . sf - The `PetscSF`
4694 
4695   Level: intermediate
4696 
4697   Note:
4698   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4699 
4700 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4701 @*/
4702 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4703 {
4704   PetscInt nroots;
4705 
4706   PetscFunctionBegin;
4707   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4708   PetscAssertPointer(sf, 2);
4709   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4710   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4711   if (nroots < 0) {
4712     PetscSection section, gSection;
4713 
4714     PetscCall(DMGetLocalSection(dm, &section));
4715     if (section) {
4716       PetscCall(DMGetGlobalSection(dm, &gSection));
4717       PetscCall(DMCreateSectionSF(dm, section, gSection));
4718     } else {
4719       *sf = NULL;
4720       PetscFunctionReturn(PETSC_SUCCESS);
4721     }
4722   }
4723   *sf = dm->sectionSF;
4724   PetscFunctionReturn(PETSC_SUCCESS);
4725 }
4726 
4727 /*@
4728   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4729 
4730   Input Parameters:
4731 + dm - The `DM`
4732 - sf - The `PetscSF`
4733 
4734   Level: intermediate
4735 
4736   Note:
4737   Any previous `PetscSF` is destroyed
4738 
4739 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4740 @*/
4741 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4742 {
4743   PetscFunctionBegin;
4744   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4745   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4746   PetscCall(PetscObjectReference((PetscObject)sf));
4747   PetscCall(PetscSFDestroy(&dm->sectionSF));
4748   dm->sectionSF = sf;
4749   PetscFunctionReturn(PETSC_SUCCESS);
4750 }
4751 
4752 /*@
4753   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4754   describing the data layout.
4755 
4756   Input Parameters:
4757 + dm            - The `DM`
4758 . localSection  - `PetscSection` describing the local data layout
4759 - globalSection - `PetscSection` describing the global data layout
4760 
4761   Level: developer
4762 
4763   Note:
4764   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4765 
4766   Developer Note:
4767   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4768   directly into the `DM`, perhaps this function should not take the local and global sections as
4769   input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing
4770   they create, this returns nothing
4771 
4772 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4773 @*/
4774 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4775 {
4776   PetscFunctionBegin;
4777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4778   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4779   PetscFunctionReturn(PETSC_SUCCESS);
4780 }
4781 
4782 /*@
4783   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4784 
4785   Not collective but the resulting `PetscSF` is collective
4786 
4787   Input Parameter:
4788 . dm - The `DM`
4789 
4790   Output Parameter:
4791 . sf - The `PetscSF`
4792 
4793   Level: intermediate
4794 
4795   Note:
4796   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4797 
4798 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4799 @*/
4800 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4801 {
4802   PetscFunctionBegin;
4803   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4804   PetscAssertPointer(sf, 2);
4805   *sf = dm->sf;
4806   PetscFunctionReturn(PETSC_SUCCESS);
4807 }
4808 
4809 /*@
4810   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4811 
4812   Collective
4813 
4814   Input Parameters:
4815 + dm - The `DM`
4816 - sf - The `PetscSF`
4817 
4818   Level: intermediate
4819 
4820 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4821 @*/
4822 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4823 {
4824   PetscFunctionBegin;
4825   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4826   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4827   PetscCall(PetscObjectReference((PetscObject)sf));
4828   PetscCall(PetscSFDestroy(&dm->sf));
4829   dm->sf = sf;
4830   PetscFunctionReturn(PETSC_SUCCESS);
4831 }
4832 
4833 /*@
4834   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4835 
4836   Input Parameter:
4837 . dm - The `DM`
4838 
4839   Output Parameter:
4840 . sf - The `PetscSF`
4841 
4842   Level: intermediate
4843 
4844   Note:
4845   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4846 
4847 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4848 @*/
4849 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4850 {
4851   PetscFunctionBegin;
4852   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4853   PetscAssertPointer(sf, 2);
4854   *sf = dm->sfNatural;
4855   PetscFunctionReturn(PETSC_SUCCESS);
4856 }
4857 
4858 /*@
4859   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4860 
4861   Input Parameters:
4862 + dm - The DM
4863 - sf - The PetscSF
4864 
4865   Level: intermediate
4866 
4867 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4868 @*/
4869 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4870 {
4871   PetscFunctionBegin;
4872   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4873   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4874   PetscCall(PetscObjectReference((PetscObject)sf));
4875   PetscCall(PetscSFDestroy(&dm->sfNatural));
4876   dm->sfNatural = sf;
4877   PetscFunctionReturn(PETSC_SUCCESS);
4878 }
4879 
4880 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4881 {
4882   PetscClassId id;
4883 
4884   PetscFunctionBegin;
4885   PetscCall(PetscObjectGetClassId(disc, &id));
4886   if (id == PETSCFE_CLASSID) {
4887     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4888   } else if (id == PETSCFV_CLASSID) {
4889     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4890   } else {
4891     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4892   }
4893   PetscFunctionReturn(PETSC_SUCCESS);
4894 }
4895 
4896 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4897 {
4898   RegionField *tmpr;
4899   PetscInt     Nf = dm->Nf, f;
4900 
4901   PetscFunctionBegin;
4902   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4903   PetscCall(PetscMalloc1(NfNew, &tmpr));
4904   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4905   for (f = Nf; f < NfNew; ++f) {
4906     tmpr[f].disc        = NULL;
4907     tmpr[f].label       = NULL;
4908     tmpr[f].avoidTensor = PETSC_FALSE;
4909   }
4910   PetscCall(PetscFree(dm->fields));
4911   dm->Nf     = NfNew;
4912   dm->fields = tmpr;
4913   PetscFunctionReturn(PETSC_SUCCESS);
4914 }
4915 
4916 /*@
4917   DMClearFields - Remove all fields from the `DM`
4918 
4919   Logically Collective
4920 
4921   Input Parameter:
4922 . dm - The `DM`
4923 
4924   Level: intermediate
4925 
4926 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4927 @*/
4928 PetscErrorCode DMClearFields(DM dm)
4929 {
4930   PetscInt f;
4931 
4932   PetscFunctionBegin;
4933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4934   for (f = 0; f < dm->Nf; ++f) {
4935     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4936     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4937   }
4938   PetscCall(PetscFree(dm->fields));
4939   dm->fields = NULL;
4940   dm->Nf     = 0;
4941   PetscFunctionReturn(PETSC_SUCCESS);
4942 }
4943 
4944 /*@
4945   DMGetNumFields - Get the number of fields in the `DM`
4946 
4947   Not Collective
4948 
4949   Input Parameter:
4950 . dm - The `DM`
4951 
4952   Output Parameter:
4953 . numFields - The number of fields
4954 
4955   Level: intermediate
4956 
4957 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4958 @*/
4959 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4960 {
4961   PetscFunctionBegin;
4962   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4963   PetscAssertPointer(numFields, 2);
4964   *numFields = dm->Nf;
4965   PetscFunctionReturn(PETSC_SUCCESS);
4966 }
4967 
4968 /*@
4969   DMSetNumFields - Set the number of fields in the `DM`
4970 
4971   Logically Collective
4972 
4973   Input Parameters:
4974 + dm        - The `DM`
4975 - numFields - The number of fields
4976 
4977   Level: intermediate
4978 
4979 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
4980 @*/
4981 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4982 {
4983   PetscInt Nf, f;
4984 
4985   PetscFunctionBegin;
4986   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4987   PetscCall(DMGetNumFields(dm, &Nf));
4988   for (f = Nf; f < numFields; ++f) {
4989     PetscContainer obj;
4990 
4991     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
4992     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
4993     PetscCall(PetscContainerDestroy(&obj));
4994   }
4995   PetscFunctionReturn(PETSC_SUCCESS);
4996 }
4997 
4998 /*@
4999   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
5000 
5001   Not Collective
5002 
5003   Input Parameters:
5004 + dm - The `DM`
5005 - f  - The field number
5006 
5007   Output Parameters:
5008 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
5009 - disc  - The discretization object (pass in `NULL` if not needed)
5010 
5011   Level: intermediate
5012 
5013 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
5014 @*/
5015 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
5016 {
5017   PetscFunctionBegin;
5018   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5019   PetscAssertPointer(disc, 4);
5020   PetscCheck((f >= 0) && (f < dm->Nf), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, dm->Nf);
5021   if (label) *label = dm->fields[f].label;
5022   if (disc) *disc = dm->fields[f].disc;
5023   PetscFunctionReturn(PETSC_SUCCESS);
5024 }
5025 
5026 /* Does not clear the DS */
5027 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5028 {
5029   PetscFunctionBegin;
5030   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
5031   PetscCall(DMLabelDestroy(&dm->fields[f].label));
5032   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
5033   dm->fields[f].label = label;
5034   dm->fields[f].disc  = disc;
5035   PetscCall(PetscObjectReference((PetscObject)label));
5036   PetscCall(PetscObjectReference(disc));
5037   PetscFunctionReturn(PETSC_SUCCESS);
5038 }
5039 
5040 /*@
5041   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
5042   the field numbering.
5043 
5044   Logically Collective
5045 
5046   Input Parameters:
5047 + dm    - The `DM`
5048 . f     - The field number
5049 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5050 - disc  - The discretization object
5051 
5052   Level: intermediate
5053 
5054 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
5055 @*/
5056 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5057 {
5058   PetscFunctionBegin;
5059   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5060   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5061   PetscValidHeader(disc, 4);
5062   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
5063   PetscCall(DMSetField_Internal(dm, f, label, disc));
5064   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
5065   PetscCall(DMClearDS(dm));
5066   PetscFunctionReturn(PETSC_SUCCESS);
5067 }
5068 
5069 /*@
5070   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
5071   and a discretization object that defines the function space associated with those points.
5072 
5073   Logically Collective
5074 
5075   Input Parameters:
5076 + dm    - The `DM`
5077 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5078 - disc  - The discretization object
5079 
5080   Level: intermediate
5081 
5082   Notes:
5083   The label already exists or will be added to the `DM` with `DMSetLabel()`.
5084 
5085   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
5086   within each cell. Thus a specific function in the space is defined by the combination of a `Vec` containing the coefficients, a `DM` defining the
5087   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5088 
5089 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5090 @*/
5091 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5092 {
5093   PetscInt Nf = dm->Nf;
5094 
5095   PetscFunctionBegin;
5096   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5097   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5098   PetscValidHeader(disc, 3);
5099   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5100   dm->fields[Nf].label = label;
5101   dm->fields[Nf].disc  = disc;
5102   PetscCall(PetscObjectReference((PetscObject)label));
5103   PetscCall(PetscObjectReference(disc));
5104   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5105   PetscCall(DMClearDS(dm));
5106   PetscFunctionReturn(PETSC_SUCCESS);
5107 }
5108 
5109 /*@
5110   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5111 
5112   Logically Collective
5113 
5114   Input Parameters:
5115 + dm          - The `DM`
5116 . f           - The field index
5117 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5118 
5119   Level: intermediate
5120 
5121 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5122 @*/
5123 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5124 {
5125   PetscFunctionBegin;
5126   PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf);
5127   dm->fields[f].avoidTensor = avoidTensor;
5128   PetscFunctionReturn(PETSC_SUCCESS);
5129 }
5130 
5131 /*@
5132   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5133 
5134   Not Collective
5135 
5136   Input Parameters:
5137 + dm - The `DM`
5138 - f  - The field index
5139 
5140   Output Parameter:
5141 . avoidTensor - The flag to avoid defining the field on tensor cells
5142 
5143   Level: intermediate
5144 
5145 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5146 @*/
5147 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5148 {
5149   PetscFunctionBegin;
5150   PetscCheck((f >= 0) && (f < dm->Nf), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", f, dm->Nf);
5151   *avoidTensor = dm->fields[f].avoidTensor;
5152   PetscFunctionReturn(PETSC_SUCCESS);
5153 }
5154 
5155 /*@
5156   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5157 
5158   Collective
5159 
5160   Input Parameters:
5161 + dm        - The `DM`
5162 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
5163 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
5164 
5165   Output Parameter:
5166 . newdm - The `DM`
5167 
5168   Level: advanced
5169 
5170 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5171 @*/
5172 PetscErrorCode DMCopyFields(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
5173 {
5174   PetscInt Nf, f;
5175 
5176   PetscFunctionBegin;
5177   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5178   PetscCall(DMGetNumFields(dm, &Nf));
5179   PetscCall(DMClearFields(newdm));
5180   for (f = 0; f < Nf; ++f) {
5181     DMLabel      label;
5182     PetscObject  field;
5183     PetscClassId id;
5184     PetscBool    useCone, useClosure;
5185 
5186     PetscCall(DMGetField(dm, f, &label, &field));
5187     PetscCall(PetscObjectGetClassId(field, &id));
5188     if (id == PETSCFE_CLASSID) {
5189       PetscFE newfe;
5190 
5191       PetscCall(PetscFELimitDegree((PetscFE)field, minDegree, maxDegree, &newfe));
5192       PetscCall(DMSetField(newdm, f, label, (PetscObject)newfe));
5193       PetscCall(PetscFEDestroy(&newfe));
5194     } else {
5195       PetscCall(DMSetField(newdm, f, label, field));
5196     }
5197     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5198     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5199   }
5200   PetscFunctionReturn(PETSC_SUCCESS);
5201 }
5202 
5203 /*@
5204   DMGetAdjacency - Returns the flags for determining variable influence
5205 
5206   Not Collective
5207 
5208   Input Parameters:
5209 + dm - The `DM` object
5210 - f  - The field number, or `PETSC_DEFAULT` for the default adjacency
5211 
5212   Output Parameters:
5213 + useCone    - Flag for variable influence starting with the cone operation
5214 - useClosure - Flag for variable influence using transitive closure
5215 
5216   Level: developer
5217 
5218   Notes:
5219 .vb
5220      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5221      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5222      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5223 .ve
5224   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5225 
5226 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5227 @*/
5228 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5229 {
5230   PetscFunctionBegin;
5231   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5232   if (useCone) PetscAssertPointer(useCone, 3);
5233   if (useClosure) PetscAssertPointer(useClosure, 4);
5234   if (f < 0) {
5235     if (useCone) *useCone = dm->adjacency[0];
5236     if (useClosure) *useClosure = dm->adjacency[1];
5237   } else {
5238     PetscInt Nf;
5239 
5240     PetscCall(DMGetNumFields(dm, &Nf));
5241     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5242     if (useCone) *useCone = dm->fields[f].adjacency[0];
5243     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5244   }
5245   PetscFunctionReturn(PETSC_SUCCESS);
5246 }
5247 
5248 /*@
5249   DMSetAdjacency - Set the flags for determining variable influence
5250 
5251   Not Collective
5252 
5253   Input Parameters:
5254 + dm         - The `DM` object
5255 . f          - The field number
5256 . useCone    - Flag for variable influence starting with the cone operation
5257 - useClosure - Flag for variable influence using transitive closure
5258 
5259   Level: developer
5260 
5261   Notes:
5262 .vb
5263      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5264      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5265      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5266 .ve
5267   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5268 
5269 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5270 @*/
5271 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5272 {
5273   PetscFunctionBegin;
5274   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5275   if (f < 0) {
5276     dm->adjacency[0] = useCone;
5277     dm->adjacency[1] = useClosure;
5278   } else {
5279     PetscInt Nf;
5280 
5281     PetscCall(DMGetNumFields(dm, &Nf));
5282     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5283     dm->fields[f].adjacency[0] = useCone;
5284     dm->fields[f].adjacency[1] = useClosure;
5285   }
5286   PetscFunctionReturn(PETSC_SUCCESS);
5287 }
5288 
5289 /*@
5290   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5291 
5292   Not collective
5293 
5294   Input Parameter:
5295 . dm - The `DM` object
5296 
5297   Output Parameters:
5298 + useCone    - Flag for variable influence starting with the cone operation
5299 - useClosure - Flag for variable influence using transitive closure
5300 
5301   Level: developer
5302 
5303   Notes:
5304 .vb
5305      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5306      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5307      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5308 .ve
5309 
5310 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5311 @*/
5312 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5313 {
5314   PetscInt Nf;
5315 
5316   PetscFunctionBegin;
5317   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5318   if (useCone) PetscAssertPointer(useCone, 2);
5319   if (useClosure) PetscAssertPointer(useClosure, 3);
5320   PetscCall(DMGetNumFields(dm, &Nf));
5321   if (!Nf) {
5322     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5323   } else {
5324     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5325   }
5326   PetscFunctionReturn(PETSC_SUCCESS);
5327 }
5328 
5329 /*@
5330   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5331 
5332   Not Collective
5333 
5334   Input Parameters:
5335 + dm         - The `DM` object
5336 . useCone    - Flag for variable influence starting with the cone operation
5337 - useClosure - Flag for variable influence using transitive closure
5338 
5339   Level: developer
5340 
5341   Notes:
5342 .vb
5343      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5344      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5345      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5346 .ve
5347 
5348 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5349 @*/
5350 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5351 {
5352   PetscInt Nf;
5353 
5354   PetscFunctionBegin;
5355   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5356   PetscCall(DMGetNumFields(dm, &Nf));
5357   if (!Nf) {
5358     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5359   } else {
5360     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5361   }
5362   PetscFunctionReturn(PETSC_SUCCESS);
5363 }
5364 
5365 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5366 {
5367   DM           plex;
5368   DMLabel     *labels, *glabels;
5369   const char **names;
5370   char        *sendNames, *recvNames;
5371   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5372   size_t       len;
5373   MPI_Comm     comm;
5374   PetscMPIInt  rank, size, p, *counts, *displs;
5375 
5376   PetscFunctionBegin;
5377   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5378   PetscCallMPI(MPI_Comm_size(comm, &size));
5379   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5380   PetscCall(DMGetNumDS(dm, &Nds));
5381   for (s = 0; s < Nds; ++s) {
5382     PetscDS  dsBC;
5383     PetscInt numBd;
5384 
5385     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5386     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5387     maxLabels += numBd;
5388   }
5389   PetscCall(PetscCalloc1(maxLabels, &labels));
5390   /* Get list of labels to be completed */
5391   for (s = 0; s < Nds; ++s) {
5392     PetscDS  dsBC;
5393     PetscInt numBd, bd;
5394 
5395     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5396     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5397     for (bd = 0; bd < numBd; ++bd) {
5398       DMLabel      label;
5399       PetscInt     field;
5400       PetscObject  obj;
5401       PetscClassId id;
5402 
5403       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5404       PetscCall(DMGetField(dm, field, NULL, &obj));
5405       PetscCall(PetscObjectGetClassId(obj, &id));
5406       if (!(id == PETSCFE_CLASSID) || !label) continue;
5407       for (l = 0; l < Nl; ++l)
5408         if (labels[l] == label) break;
5409       if (l == Nl) labels[Nl++] = label;
5410     }
5411   }
5412   /* Get label names */
5413   PetscCall(PetscMalloc1(Nl, &names));
5414   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5415   for (l = 0; l < Nl; ++l) {
5416     PetscCall(PetscStrlen(names[l], &len));
5417     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5418   }
5419   PetscCall(PetscFree(labels));
5420   PetscCallMPI(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5421   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5422   for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5423   PetscCall(PetscFree(names));
5424   /* Put all names on all processes */
5425   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5426   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5427   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5428   gNl = displs[size];
5429   for (p = 0; p < size; ++p) {
5430     counts[p] *= gmaxLen;
5431     displs[p] *= gmaxLen;
5432   }
5433   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5434   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5435   PetscCall(PetscFree2(counts, displs));
5436   PetscCall(PetscFree(sendNames));
5437   for (l = 0, gl = 0; l < gNl; ++l) {
5438     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5439     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5440     for (m = 0; m < gl; ++m)
5441       if (glabels[m] == glabels[gl]) goto next_label;
5442     PetscCall(DMConvert(dm, DMPLEX, &plex));
5443     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5444     PetscCall(DMDestroy(&plex));
5445     ++gl;
5446   next_label:
5447     continue;
5448   }
5449   PetscCall(PetscFree2(recvNames, glabels));
5450   PetscFunctionReturn(PETSC_SUCCESS);
5451 }
5452 
5453 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5454 {
5455   DMSpace *tmpd;
5456   PetscInt Nds = dm->Nds, s;
5457 
5458   PetscFunctionBegin;
5459   if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5460   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5461   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5462   for (s = Nds; s < NdsNew; ++s) {
5463     tmpd[s].ds     = NULL;
5464     tmpd[s].label  = NULL;
5465     tmpd[s].fields = NULL;
5466   }
5467   PetscCall(PetscFree(dm->probs));
5468   dm->Nds   = NdsNew;
5469   dm->probs = tmpd;
5470   PetscFunctionReturn(PETSC_SUCCESS);
5471 }
5472 
5473 /*@
5474   DMGetNumDS - Get the number of discrete systems in the `DM`
5475 
5476   Not Collective
5477 
5478   Input Parameter:
5479 . dm - The `DM`
5480 
5481   Output Parameter:
5482 . Nds - The number of `PetscDS` objects
5483 
5484   Level: intermediate
5485 
5486 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5487 @*/
5488 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5489 {
5490   PetscFunctionBegin;
5491   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5492   PetscAssertPointer(Nds, 2);
5493   *Nds = dm->Nds;
5494   PetscFunctionReturn(PETSC_SUCCESS);
5495 }
5496 
5497 /*@
5498   DMClearDS - Remove all discrete systems from the `DM`
5499 
5500   Logically Collective
5501 
5502   Input Parameter:
5503 . dm - The `DM`
5504 
5505   Level: intermediate
5506 
5507 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5508 @*/
5509 PetscErrorCode DMClearDS(DM dm)
5510 {
5511   PetscInt s;
5512 
5513   PetscFunctionBegin;
5514   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5515   for (s = 0; s < dm->Nds; ++s) {
5516     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5517     PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5518     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5519     PetscCall(ISDestroy(&dm->probs[s].fields));
5520   }
5521   PetscCall(PetscFree(dm->probs));
5522   dm->probs = NULL;
5523   dm->Nds   = 0;
5524   PetscFunctionReturn(PETSC_SUCCESS);
5525 }
5526 
5527 /*@
5528   DMGetDS - Get the default `PetscDS`
5529 
5530   Not Collective
5531 
5532   Input Parameter:
5533 . dm - The `DM`
5534 
5535   Output Parameter:
5536 . ds - The default `PetscDS`
5537 
5538   Level: intermediate
5539 
5540 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5541 @*/
5542 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5543 {
5544   PetscFunctionBeginHot;
5545   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5546   PetscAssertPointer(ds, 2);
5547   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5548   *ds = dm->probs[0].ds;
5549   PetscFunctionReturn(PETSC_SUCCESS);
5550 }
5551 
5552 /*@
5553   DMGetCellDS - Get the `PetscDS` defined on a given cell
5554 
5555   Not Collective
5556 
5557   Input Parameters:
5558 + dm    - The `DM`
5559 - point - Cell for the `PetscDS`
5560 
5561   Output Parameters:
5562 + ds   - The `PetscDS` defined on the given cell
5563 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds
5564 
5565   Level: developer
5566 
5567 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5568 @*/
5569 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5570 {
5571   PetscDS  dsDef = NULL;
5572   PetscInt s;
5573 
5574   PetscFunctionBeginHot;
5575   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5576   if (ds) PetscAssertPointer(ds, 3);
5577   if (dsIn) PetscAssertPointer(dsIn, 4);
5578   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5579   if (ds) *ds = NULL;
5580   if (dsIn) *dsIn = NULL;
5581   for (s = 0; s < dm->Nds; ++s) {
5582     PetscInt val;
5583 
5584     if (!dm->probs[s].label) {
5585       dsDef = dm->probs[s].ds;
5586     } else {
5587       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5588       if (val >= 0) {
5589         if (ds) *ds = dm->probs[s].ds;
5590         if (dsIn) *dsIn = dm->probs[s].dsIn;
5591         break;
5592       }
5593     }
5594   }
5595   if (ds && !*ds) *ds = dsDef;
5596   PetscFunctionReturn(PETSC_SUCCESS);
5597 }
5598 
5599 /*@
5600   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5601 
5602   Not Collective
5603 
5604   Input Parameters:
5605 + dm    - The `DM`
5606 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5607 
5608   Output Parameters:
5609 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5610 . ds     - The `PetscDS` defined on the given region, or `NULL`
5611 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5612 
5613   Level: advanced
5614 
5615   Note:
5616   If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5617   the `PetscDS` for the full domain (if present) is returned. Returns with
5618   fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5619 
5620 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5621 @*/
5622 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5623 {
5624   PetscInt Nds = dm->Nds, s;
5625 
5626   PetscFunctionBegin;
5627   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5628   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5629   if (fields) {
5630     PetscAssertPointer(fields, 3);
5631     *fields = NULL;
5632   }
5633   if (ds) {
5634     PetscAssertPointer(ds, 4);
5635     *ds = NULL;
5636   }
5637   if (dsIn) {
5638     PetscAssertPointer(dsIn, 5);
5639     *dsIn = NULL;
5640   }
5641   for (s = 0; s < Nds; ++s) {
5642     if (dm->probs[s].label == label || !dm->probs[s].label) {
5643       if (fields) *fields = dm->probs[s].fields;
5644       if (ds) *ds = dm->probs[s].ds;
5645       if (dsIn) *dsIn = dm->probs[s].dsIn;
5646       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5647     }
5648   }
5649   PetscFunctionReturn(PETSC_SUCCESS);
5650 }
5651 
5652 /*@
5653   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5654 
5655   Collective
5656 
5657   Input Parameters:
5658 + dm     - The `DM`
5659 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5660 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5661 . ds     - The `PetscDS` defined on the given region
5662 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5663 
5664   Level: advanced
5665 
5666   Note:
5667   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5668   the fields argument is ignored.
5669 
5670 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5671 @*/
5672 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5673 {
5674   PetscInt Nds = dm->Nds, s;
5675 
5676   PetscFunctionBegin;
5677   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5678   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5679   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5680   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5681   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5682   for (s = 0; s < Nds; ++s) {
5683     if (dm->probs[s].label == label) {
5684       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5685       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5686       dm->probs[s].ds   = ds;
5687       dm->probs[s].dsIn = dsIn;
5688       PetscFunctionReturn(PETSC_SUCCESS);
5689     }
5690   }
5691   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5692   PetscCall(PetscObjectReference((PetscObject)label));
5693   PetscCall(PetscObjectReference((PetscObject)fields));
5694   PetscCall(PetscObjectReference((PetscObject)ds));
5695   PetscCall(PetscObjectReference((PetscObject)dsIn));
5696   if (!label) {
5697     /* Put the NULL label at the front, so it is returned as the default */
5698     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5699     Nds = 0;
5700   }
5701   dm->probs[Nds].label  = label;
5702   dm->probs[Nds].fields = fields;
5703   dm->probs[Nds].ds     = ds;
5704   dm->probs[Nds].dsIn   = dsIn;
5705   PetscFunctionReturn(PETSC_SUCCESS);
5706 }
5707 
5708 /*@
5709   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5710 
5711   Not Collective
5712 
5713   Input Parameters:
5714 + dm  - The `DM`
5715 - num - The region number, in [0, Nds)
5716 
5717   Output Parameters:
5718 + label  - The region label, or `NULL`
5719 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5720 . ds     - The `PetscDS` defined on the given region, or `NULL`
5721 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5722 
5723   Level: advanced
5724 
5725 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5726 @*/
5727 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5728 {
5729   PetscInt Nds;
5730 
5731   PetscFunctionBegin;
5732   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5733   PetscCall(DMGetNumDS(dm, &Nds));
5734   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5735   if (label) {
5736     PetscAssertPointer(label, 3);
5737     *label = dm->probs[num].label;
5738   }
5739   if (fields) {
5740     PetscAssertPointer(fields, 4);
5741     *fields = dm->probs[num].fields;
5742   }
5743   if (ds) {
5744     PetscAssertPointer(ds, 5);
5745     *ds = dm->probs[num].ds;
5746   }
5747   if (dsIn) {
5748     PetscAssertPointer(dsIn, 6);
5749     *dsIn = dm->probs[num].dsIn;
5750   }
5751   PetscFunctionReturn(PETSC_SUCCESS);
5752 }
5753 
5754 /*@
5755   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5756 
5757   Not Collective
5758 
5759   Input Parameters:
5760 + dm     - The `DM`
5761 . num    - The region number, in [0, Nds)
5762 . label  - The region label, or `NULL`
5763 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5764 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5765 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5766 
5767   Level: advanced
5768 
5769 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5770 @*/
5771 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5772 {
5773   PetscInt Nds;
5774 
5775   PetscFunctionBegin;
5776   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5777   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5778   PetscCall(DMGetNumDS(dm, &Nds));
5779   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5780   PetscCall(PetscObjectReference((PetscObject)label));
5781   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5782   dm->probs[num].label = label;
5783   if (fields) {
5784     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5785     PetscCall(PetscObjectReference((PetscObject)fields));
5786     PetscCall(ISDestroy(&dm->probs[num].fields));
5787     dm->probs[num].fields = fields;
5788   }
5789   if (ds) {
5790     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5791     PetscCall(PetscObjectReference((PetscObject)ds));
5792     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5793     dm->probs[num].ds = ds;
5794   }
5795   if (dsIn) {
5796     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5797     PetscCall(PetscObjectReference((PetscObject)dsIn));
5798     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5799     dm->probs[num].dsIn = dsIn;
5800   }
5801   PetscFunctionReturn(PETSC_SUCCESS);
5802 }
5803 
5804 /*@
5805   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5806 
5807   Not Collective
5808 
5809   Input Parameters:
5810 + dm - The `DM`
5811 - ds - The `PetscDS` defined on the given region
5812 
5813   Output Parameter:
5814 . num - The region number, in [0, Nds), or -1 if not found
5815 
5816   Level: advanced
5817 
5818 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5819 @*/
5820 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5821 {
5822   PetscInt Nds, n;
5823 
5824   PetscFunctionBegin;
5825   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5826   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5827   PetscAssertPointer(num, 3);
5828   PetscCall(DMGetNumDS(dm, &Nds));
5829   for (n = 0; n < Nds; ++n)
5830     if (ds == dm->probs[n].ds) break;
5831   if (n >= Nds) *num = -1;
5832   else *num = n;
5833   PetscFunctionReturn(PETSC_SUCCESS);
5834 }
5835 
5836 /*@
5837   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5838 
5839   Not Collective
5840 
5841   Input Parameters:
5842 + dm     - The `DM`
5843 . Nc     - The number of components for the field
5844 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5845 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5846 
5847   Output Parameter:
5848 . fem - The `PetscFE`
5849 
5850   Level: intermediate
5851 
5852   Note:
5853   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5854 
5855 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5856 @*/
5857 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5858 {
5859   DMPolytopeType ct;
5860   PetscInt       dim, cStart;
5861 
5862   PetscFunctionBegin;
5863   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5864   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5865   if (prefix) PetscAssertPointer(prefix, 3);
5866   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5867   PetscAssertPointer(fem, 5);
5868   PetscCall(DMGetDimension(dm, &dim));
5869   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5870   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5871   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5872   PetscFunctionReturn(PETSC_SUCCESS);
5873 }
5874 
5875 /*@
5876   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5877 
5878   Collective
5879 
5880   Input Parameter:
5881 . dm - The `DM`
5882 
5883   Options Database Key:
5884 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5885 
5886   Level: intermediate
5887 
5888 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5889 @*/
5890 PetscErrorCode DMCreateDS(DM dm)
5891 {
5892   MPI_Comm  comm;
5893   PetscDS   dsDef;
5894   DMLabel  *labelSet;
5895   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5896   PetscBool doSetup = PETSC_TRUE, flg;
5897 
5898   PetscFunctionBegin;
5899   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5900   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5901   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5902   PetscCall(DMGetCoordinateDim(dm, &dE));
5903   /* Determine how many regions we have */
5904   PetscCall(PetscMalloc1(Nf, &labelSet));
5905   Nl   = 0;
5906   Ndef = 0;
5907   for (f = 0; f < Nf; ++f) {
5908     DMLabel  label = dm->fields[f].label;
5909     PetscInt l;
5910 
5911 #ifdef PETSC_HAVE_LIBCEED
5912     /* Move CEED context to discretizations */
5913     {
5914       PetscClassId id;
5915 
5916       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5917       if (id == PETSCFE_CLASSID) {
5918         Ceed ceed;
5919 
5920         PetscCall(DMGetCeed(dm, &ceed));
5921         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5922       }
5923     }
5924 #endif
5925     if (!label) {
5926       ++Ndef;
5927       continue;
5928     }
5929     for (l = 0; l < Nl; ++l)
5930       if (label == labelSet[l]) break;
5931     if (l < Nl) continue;
5932     labelSet[Nl++] = label;
5933   }
5934   /* Create default DS if there are no labels to intersect with */
5935   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5936   if (!dsDef && Ndef && !Nl) {
5937     IS        fields;
5938     PetscInt *fld, nf;
5939 
5940     for (f = 0, nf = 0; f < Nf; ++f)
5941       if (!dm->fields[f].label) ++nf;
5942     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5943     PetscCall(PetscMalloc1(nf, &fld));
5944     for (f = 0, nf = 0; f < Nf; ++f)
5945       if (!dm->fields[f].label) fld[nf++] = f;
5946     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5947     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5948     PetscCall(ISSetType(fields, ISGENERAL));
5949     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5950 
5951     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5952     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5953     PetscCall(PetscDSDestroy(&dsDef));
5954     PetscCall(ISDestroy(&fields));
5955   }
5956   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5957   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5958   /* Intersect labels with default fields */
5959   if (Ndef && Nl) {
5960     DM              plex;
5961     DMLabel         cellLabel;
5962     IS              fieldIS, allcellIS, defcellIS = NULL;
5963     PetscInt       *fields;
5964     const PetscInt *cells;
5965     PetscInt        depth, nf = 0, n, c;
5966 
5967     PetscCall(DMConvert(dm, DMPLEX, &plex));
5968     PetscCall(DMPlexGetDepth(plex, &depth));
5969     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5970     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5971     /* TODO This looks like it only works for one label */
5972     for (l = 0; l < Nl; ++l) {
5973       DMLabel label = labelSet[l];
5974       IS      pointIS;
5975 
5976       PetscCall(ISDestroy(&defcellIS));
5977       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5978       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5979       PetscCall(ISDestroy(&pointIS));
5980     }
5981     PetscCall(ISDestroy(&allcellIS));
5982 
5983     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5984     PetscCall(ISGetLocalSize(defcellIS, &n));
5985     PetscCall(ISGetIndices(defcellIS, &cells));
5986     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5987     PetscCall(ISRestoreIndices(defcellIS, &cells));
5988     PetscCall(ISDestroy(&defcellIS));
5989     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5990 
5991     PetscCall(PetscMalloc1(Ndef, &fields));
5992     for (f = 0; f < Nf; ++f)
5993       if (!dm->fields[f].label) fields[nf++] = f;
5994     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
5995     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
5996     PetscCall(ISSetType(fieldIS, ISGENERAL));
5997     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
5998 
5999     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
6000     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
6001     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6002     PetscCall(DMLabelDestroy(&cellLabel));
6003     PetscCall(PetscDSDestroy(&dsDef));
6004     PetscCall(ISDestroy(&fieldIS));
6005     PetscCall(DMDestroy(&plex));
6006   }
6007   /* Create label DSes
6008      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
6009   */
6010   /* TODO Should check that labels are disjoint */
6011   for (l = 0; l < Nl; ++l) {
6012     DMLabel   label = labelSet[l];
6013     PetscDS   ds, dsIn = NULL;
6014     IS        fields;
6015     PetscInt *fld, nf;
6016 
6017     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
6018     for (f = 0, nf = 0; f < Nf; ++f)
6019       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
6020     PetscCall(PetscMalloc1(nf, &fld));
6021     for (f = 0, nf = 0; f < Nf; ++f)
6022       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
6023     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
6024     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
6025     PetscCall(ISSetType(fields, ISGENERAL));
6026     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
6027     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
6028     {
6029       DMPolytopeType ct;
6030       PetscInt       lStart, lEnd;
6031       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
6032 
6033       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
6034       if (lStart >= 0) {
6035         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
6036         switch (ct) {
6037         case DM_POLYTOPE_POINT_PRISM_TENSOR:
6038         case DM_POLYTOPE_SEG_PRISM_TENSOR:
6039         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6040         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
6041           isCohesiveLocal = PETSC_TRUE;
6042           break;
6043         default:
6044           break;
6045         }
6046       }
6047       PetscCallMPI(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
6048       if (isCohesive) {
6049         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
6050         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
6051       }
6052       for (f = 0, nf = 0; f < Nf; ++f) {
6053         if (label == dm->fields[f].label || !dm->fields[f].label) {
6054           if (label == dm->fields[f].label) {
6055             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
6056             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
6057             if (dsIn) {
6058               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
6059               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
6060             }
6061           }
6062           ++nf;
6063         }
6064       }
6065     }
6066     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
6067     PetscCall(ISDestroy(&fields));
6068     PetscCall(PetscDSDestroy(&ds));
6069     PetscCall(PetscDSDestroy(&dsIn));
6070   }
6071   PetscCall(PetscFree(labelSet));
6072   /* Set fields in DSes */
6073   for (s = 0; s < dm->Nds; ++s) {
6074     PetscDS         ds     = dm->probs[s].ds;
6075     PetscDS         dsIn   = dm->probs[s].dsIn;
6076     IS              fields = dm->probs[s].fields;
6077     const PetscInt *fld;
6078     PetscInt        nf, dsnf;
6079     PetscBool       isCohesive;
6080 
6081     PetscCall(PetscDSGetNumFields(ds, &dsnf));
6082     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
6083     PetscCall(ISGetLocalSize(fields, &nf));
6084     PetscCall(ISGetIndices(fields, &fld));
6085     for (f = 0; f < nf; ++f) {
6086       PetscObject  disc = dm->fields[fld[f]].disc;
6087       PetscBool    isCohesiveField;
6088       PetscClassId id;
6089 
6090       /* Handle DS with no fields */
6091       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
6092       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
6093       if (isCohesive) {
6094         if (!isCohesiveField) {
6095           PetscObject bdDisc;
6096 
6097           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
6098           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
6099           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6100         } else {
6101           PetscCall(PetscDSSetDiscretization(ds, f, disc));
6102           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6103         }
6104       } else {
6105         PetscCall(PetscDSSetDiscretization(ds, f, disc));
6106       }
6107       /* We allow people to have placeholder fields and construct the Section by hand */
6108       PetscCall(PetscObjectGetClassId(disc, &id));
6109       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
6110     }
6111     PetscCall(ISRestoreIndices(fields, &fld));
6112   }
6113   /* Allow k-jet tabulation */
6114   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6115   if (flg) {
6116     for (s = 0; s < dm->Nds; ++s) {
6117       PetscDS  ds   = dm->probs[s].ds;
6118       PetscDS  dsIn = dm->probs[s].dsIn;
6119       PetscInt Nf, f;
6120 
6121       PetscCall(PetscDSGetNumFields(ds, &Nf));
6122       for (f = 0; f < Nf; ++f) {
6123         PetscCall(PetscDSSetJetDegree(ds, f, k));
6124         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6125       }
6126     }
6127   }
6128   /* Setup DSes */
6129   if (doSetup) {
6130     for (s = 0; s < dm->Nds; ++s) {
6131       if (dm->setfromoptionscalled) {
6132         PetscCall(PetscDSSetFromOptions(dm->probs[s].ds));
6133         if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn));
6134       }
6135       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6136       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6137     }
6138   }
6139   PetscFunctionReturn(PETSC_SUCCESS);
6140 }
6141 
6142 /*@
6143   DMUseTensorOrder - Use a tensor product closure ordering for the default section
6144 
6145   Input Parameters:
6146 + dm     - The DM
6147 - tensor - Flag for tensor order
6148 
6149   Level: developer
6150 
6151 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()`
6152 @*/
6153 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor)
6154 {
6155   PetscInt  Nf;
6156   PetscBool reorder = PETSC_TRUE, isPlex;
6157 
6158   PetscFunctionBegin;
6159   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
6160   PetscCall(DMGetNumFields(dm, &Nf));
6161   for (PetscInt f = 0; f < Nf; ++f) {
6162     PetscObject  obj;
6163     PetscClassId id;
6164 
6165     PetscCall(DMGetField(dm, f, NULL, &obj));
6166     PetscCall(PetscObjectGetClassId(obj, &id));
6167     if (id == PETSCFE_CLASSID) {
6168       PetscSpace sp;
6169       PetscBool  tensor;
6170 
6171       PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp));
6172       PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor));
6173       reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE;
6174     } else reorder = PETSC_FALSE;
6175   }
6176   if (tensor) {
6177     if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
6178   } else {
6179     PetscSection s;
6180 
6181     PetscCall(DMGetLocalSection(dm, &s));
6182     if (s) PetscCall(PetscSectionResetClosurePermutation(s));
6183   }
6184   PetscFunctionReturn(PETSC_SUCCESS);
6185 }
6186 
6187 /*@
6188   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6189 
6190   Collective
6191 
6192   Input Parameters:
6193 + dm   - The `DM`
6194 - time - The time
6195 
6196   Output Parameters:
6197 + u   - The vector will be filled with exact solution values, or `NULL`
6198 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6199 
6200   Level: developer
6201 
6202   Note:
6203   The user must call `PetscDSSetExactSolution()` before using this routine
6204 
6205 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6206 @*/
6207 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6208 {
6209   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6210   void   **ectxs;
6211   Vec      locu, locu_t;
6212   PetscInt Nf, Nds, s;
6213 
6214   PetscFunctionBegin;
6215   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6216   if (u) {
6217     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6218     PetscCall(DMGetLocalVector(dm, &locu));
6219     PetscCall(VecSet(locu, 0.));
6220   }
6221   if (u_t) {
6222     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6223     PetscCall(DMGetLocalVector(dm, &locu_t));
6224     PetscCall(VecSet(locu_t, 0.));
6225   }
6226   PetscCall(DMGetNumFields(dm, &Nf));
6227   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6228   PetscCall(DMGetNumDS(dm, &Nds));
6229   for (s = 0; s < Nds; ++s) {
6230     PetscDS         ds;
6231     DMLabel         label;
6232     IS              fieldIS;
6233     const PetscInt *fields, id = 1;
6234     PetscInt        dsNf, f;
6235 
6236     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6237     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6238     PetscCall(ISGetIndices(fieldIS, &fields));
6239     PetscCall(PetscArrayzero(exacts, Nf));
6240     PetscCall(PetscArrayzero(ectxs, Nf));
6241     if (u) {
6242       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6243       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6244       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6245     }
6246     if (u_t) {
6247       PetscCall(PetscArrayzero(exacts, Nf));
6248       PetscCall(PetscArrayzero(ectxs, Nf));
6249       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6250       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6251       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6252     }
6253     PetscCall(ISRestoreIndices(fieldIS, &fields));
6254   }
6255   if (u) {
6256     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6257     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6258   }
6259   if (u_t) {
6260     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6261     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6262   }
6263   PetscCall(PetscFree2(exacts, ectxs));
6264   if (u) {
6265     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6266     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6267     PetscCall(DMRestoreLocalVector(dm, &locu));
6268   }
6269   if (u_t) {
6270     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6271     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6272     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6273   }
6274   PetscFunctionReturn(PETSC_SUCCESS);
6275 }
6276 
6277 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscInt minDegree, PetscInt maxDegree, PetscDS ds, PetscDS dsIn)
6278 {
6279   PetscDS dsNew, dsInNew = NULL;
6280 
6281   PetscFunctionBegin;
6282   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6283   PetscCall(PetscDSCopy(ds, minDegree, maxDegree, dm, dsNew));
6284   if (dsIn) {
6285     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6286     PetscCall(PetscDSCopy(dsIn, minDegree, maxDegree, dm, dsInNew));
6287   }
6288   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6289   PetscCall(PetscDSDestroy(&dsNew));
6290   PetscCall(PetscDSDestroy(&dsInNew));
6291   PetscFunctionReturn(PETSC_SUCCESS);
6292 }
6293 
6294 /*@
6295   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6296 
6297   Collective
6298 
6299   Input Parameters:
6300 + dm        - The `DM`
6301 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
6302 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
6303 
6304   Output Parameter:
6305 . newdm - The `DM`
6306 
6307   Level: advanced
6308 
6309 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6310 @*/
6311 PetscErrorCode DMCopyDS(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
6312 {
6313   PetscInt Nds, s;
6314 
6315   PetscFunctionBegin;
6316   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6317   PetscCall(DMGetNumDS(dm, &Nds));
6318   PetscCall(DMClearDS(newdm));
6319   for (s = 0; s < Nds; ++s) {
6320     DMLabel  label;
6321     IS       fields;
6322     PetscDS  ds, dsIn, newds;
6323     PetscInt Nbd, bd;
6324 
6325     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6326     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6327     PetscCall(DMTransferDS_Internal(newdm, label, fields, minDegree, maxDegree, ds, dsIn));
6328     /* Complete new labels in the new DS */
6329     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6330     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6331     for (bd = 0; bd < Nbd; ++bd) {
6332       PetscWeakForm wf;
6333       DMLabel       label;
6334       PetscInt      field;
6335 
6336       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6337       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6338     }
6339   }
6340   PetscCall(DMCompleteBCLabels_Internal(newdm));
6341   PetscFunctionReturn(PETSC_SUCCESS);
6342 }
6343 
6344 /*@
6345   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6346 
6347   Collective
6348 
6349   Input Parameter:
6350 . dm - The `DM`
6351 
6352   Output Parameter:
6353 . newdm - The `DM`
6354 
6355   Level: advanced
6356 
6357   Developer Note:
6358   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6359 
6360 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6361 @*/
6362 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6363 {
6364   PetscFunctionBegin;
6365   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6366   PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6367   PetscFunctionReturn(PETSC_SUCCESS);
6368 }
6369 
6370 /*@
6371   DMGetDimension - Return the topological dimension of the `DM`
6372 
6373   Not Collective
6374 
6375   Input Parameter:
6376 . dm - The `DM`
6377 
6378   Output Parameter:
6379 . dim - The topological dimension
6380 
6381   Level: beginner
6382 
6383 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6384 @*/
6385 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6386 {
6387   PetscFunctionBegin;
6388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6389   PetscAssertPointer(dim, 2);
6390   *dim = dm->dim;
6391   PetscFunctionReturn(PETSC_SUCCESS);
6392 }
6393 
6394 /*@
6395   DMSetDimension - Set the topological dimension of the `DM`
6396 
6397   Collective
6398 
6399   Input Parameters:
6400 + dm  - The `DM`
6401 - dim - The topological dimension
6402 
6403   Level: beginner
6404 
6405 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6406 @*/
6407 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6408 {
6409   PetscDS  ds;
6410   PetscInt Nds, n;
6411 
6412   PetscFunctionBegin;
6413   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6414   PetscValidLogicalCollectiveInt(dm, dim, 2);
6415   dm->dim = dim;
6416   if (dm->dim >= 0) {
6417     PetscCall(DMGetNumDS(dm, &Nds));
6418     for (n = 0; n < Nds; ++n) {
6419       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6420       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6421     }
6422   }
6423   PetscFunctionReturn(PETSC_SUCCESS);
6424 }
6425 
6426 /*@
6427   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6428 
6429   Collective
6430 
6431   Input Parameters:
6432 + dm  - the `DM`
6433 - dim - the dimension
6434 
6435   Output Parameters:
6436 + pStart - The first point of the given dimension
6437 - pEnd   - The first point following points of the given dimension
6438 
6439   Level: intermediate
6440 
6441   Note:
6442   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6443   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6444   then the interval is empty.
6445 
6446 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6447 @*/
6448 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6449 {
6450   PetscInt d;
6451 
6452   PetscFunctionBegin;
6453   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6454   PetscCall(DMGetDimension(dm, &d));
6455   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6456   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6457   PetscFunctionReturn(PETSC_SUCCESS);
6458 }
6459 
6460 /*@
6461   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6462 
6463   Collective
6464 
6465   Input Parameter:
6466 . dm - The original `DM`
6467 
6468   Output Parameter:
6469 . odm - The `DM` which provides the layout for output
6470 
6471   Level: intermediate
6472 
6473   Note:
6474   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6475   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6476   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6477 
6478 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6479 @*/
6480 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6481 {
6482   PetscSection section;
6483   IS           perm;
6484   PetscBool    hasConstraints, newDM, gnewDM;
6485 
6486   PetscFunctionBegin;
6487   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6488   PetscAssertPointer(odm, 2);
6489   PetscCall(DMGetLocalSection(dm, &section));
6490   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6491   PetscCall(PetscSectionGetPermutation(section, &perm));
6492   newDM = hasConstraints || perm ? PETSC_TRUE : PETSC_FALSE;
6493   PetscCallMPI(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6494   if (!gnewDM) {
6495     *odm = dm;
6496     PetscFunctionReturn(PETSC_SUCCESS);
6497   }
6498   if (!dm->dmBC) {
6499     PetscSection newSection, gsection;
6500     PetscSF      sf;
6501     PetscBool    usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE;
6502 
6503     PetscCall(DMClone(dm, &dm->dmBC));
6504     PetscCall(DMCopyDisc(dm, dm->dmBC));
6505     PetscCall(PetscSectionClone(section, &newSection));
6506     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6507     PetscCall(PetscSectionDestroy(&newSection));
6508     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6509     PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection));
6510     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6511     PetscCall(PetscSectionDestroy(&gsection));
6512   }
6513   *odm = dm->dmBC;
6514   PetscFunctionReturn(PETSC_SUCCESS);
6515 }
6516 
6517 /*@
6518   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6519 
6520   Input Parameter:
6521 . dm - The original `DM`
6522 
6523   Output Parameters:
6524 + num - The output sequence number
6525 - val - The output sequence value
6526 
6527   Level: intermediate
6528 
6529   Note:
6530   This is intended for output that should appear in sequence, for instance
6531   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6532 
6533   Developer Note:
6534   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6535   not directly related to the `DM`.
6536 
6537 .seealso: [](ch_dmbase), `DM`, `VecView()`
6538 @*/
6539 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6540 {
6541   PetscFunctionBegin;
6542   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6543   if (num) {
6544     PetscAssertPointer(num, 2);
6545     *num = dm->outputSequenceNum;
6546   }
6547   if (val) {
6548     PetscAssertPointer(val, 3);
6549     *val = dm->outputSequenceVal;
6550   }
6551   PetscFunctionReturn(PETSC_SUCCESS);
6552 }
6553 
6554 /*@
6555   DMSetOutputSequenceNumber - Set the sequence number/value for output
6556 
6557   Input Parameters:
6558 + dm  - The original `DM`
6559 . num - The output sequence number
6560 - val - The output sequence value
6561 
6562   Level: intermediate
6563 
6564   Note:
6565   This is intended for output that should appear in sequence, for instance
6566   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6567 
6568 .seealso: [](ch_dmbase), `DM`, `VecView()`
6569 @*/
6570 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6571 {
6572   PetscFunctionBegin;
6573   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6574   dm->outputSequenceNum = num;
6575   dm->outputSequenceVal = val;
6576   PetscFunctionReturn(PETSC_SUCCESS);
6577 }
6578 
6579 /*@
6580   DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6581 
6582   Input Parameters:
6583 + dm     - The original `DM`
6584 . viewer - The `PetscViewer` to get it from
6585 . name   - The sequence name
6586 - num    - The output sequence number
6587 
6588   Output Parameter:
6589 . val - The output sequence value
6590 
6591   Level: intermediate
6592 
6593   Note:
6594   This is intended for output that should appear in sequence, for instance
6595   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6596 
6597   Developer Note:
6598   It is unclear at the user API level why a `DM` is needed as input
6599 
6600 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6601 @*/
6602 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val)
6603 {
6604   PetscBool ishdf5;
6605 
6606   PetscFunctionBegin;
6607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6608   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6609   PetscAssertPointer(name, 3);
6610   PetscAssertPointer(val, 5);
6611   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6612   if (ishdf5) {
6613 #if defined(PETSC_HAVE_HDF5)
6614     PetscScalar value;
6615 
6616     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6617     *val = PetscRealPart(value);
6618 #endif
6619   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6620   PetscFunctionReturn(PETSC_SUCCESS);
6621 }
6622 
6623 /*@
6624   DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer`
6625 
6626   Input Parameters:
6627 + dm     - The original `DM`
6628 . viewer - The `PetscViewer` to get it from
6629 - name   - The sequence name
6630 
6631   Output Parameter:
6632 . len - The length of the output sequence
6633 
6634   Level: intermediate
6635 
6636   Note:
6637   This is intended for output that should appear in sequence, for instance
6638   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6639 
6640   Developer Note:
6641   It is unclear at the user API level why a `DM` is needed as input
6642 
6643 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6644 @*/
6645 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len)
6646 {
6647   PetscBool ishdf5;
6648 
6649   PetscFunctionBegin;
6650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6651   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6652   PetscAssertPointer(name, 3);
6653   PetscAssertPointer(len, 4);
6654   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6655   if (ishdf5) {
6656 #if defined(PETSC_HAVE_HDF5)
6657     PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer));
6658 #endif
6659   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6660   PetscFunctionReturn(PETSC_SUCCESS);
6661 }
6662 
6663 /*@
6664   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6665 
6666   Not Collective
6667 
6668   Input Parameter:
6669 . dm - The `DM`
6670 
6671   Output Parameter:
6672 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6673 
6674   Level: beginner
6675 
6676 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6677 @*/
6678 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6679 {
6680   PetscFunctionBegin;
6681   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6682   PetscAssertPointer(useNatural, 2);
6683   *useNatural = dm->useNatural;
6684   PetscFunctionReturn(PETSC_SUCCESS);
6685 }
6686 
6687 /*@
6688   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6689 
6690   Collective
6691 
6692   Input Parameters:
6693 + dm         - The `DM`
6694 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6695 
6696   Level: beginner
6697 
6698   Note:
6699   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6700 
6701 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6702 @*/
6703 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6704 {
6705   PetscFunctionBegin;
6706   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6707   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6708   dm->useNatural = useNatural;
6709   PetscFunctionReturn(PETSC_SUCCESS);
6710 }
6711 
6712 /*@
6713   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6714 
6715   Not Collective
6716 
6717   Input Parameters:
6718 + dm   - The `DM` object
6719 - name - The label name
6720 
6721   Level: intermediate
6722 
6723 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6724 @*/
6725 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6726 {
6727   PetscBool flg;
6728   DMLabel   label;
6729 
6730   PetscFunctionBegin;
6731   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6732   PetscAssertPointer(name, 2);
6733   PetscCall(DMHasLabel(dm, name, &flg));
6734   if (!flg) {
6735     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6736     PetscCall(DMAddLabel(dm, label));
6737     PetscCall(DMLabelDestroy(&label));
6738   }
6739   PetscFunctionReturn(PETSC_SUCCESS);
6740 }
6741 
6742 /*@
6743   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6744 
6745   Not Collective
6746 
6747   Input Parameters:
6748 + dm   - The `DM` object
6749 . l    - The index for the label
6750 - name - The label name
6751 
6752   Level: intermediate
6753 
6754 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6755 @*/
6756 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6757 {
6758   DMLabelLink orig, prev = NULL;
6759   DMLabel     label;
6760   PetscInt    Nl, m;
6761   PetscBool   flg, match;
6762   const char *lname;
6763 
6764   PetscFunctionBegin;
6765   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6766   PetscAssertPointer(name, 3);
6767   PetscCall(DMHasLabel(dm, name, &flg));
6768   if (!flg) {
6769     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6770     PetscCall(DMAddLabel(dm, label));
6771     PetscCall(DMLabelDestroy(&label));
6772   }
6773   PetscCall(DMGetNumLabels(dm, &Nl));
6774   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6775   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6776     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6777     PetscCall(PetscStrcmp(name, lname, &match));
6778     if (match) break;
6779   }
6780   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6781   if (!m) dm->labels = orig->next;
6782   else prev->next = orig->next;
6783   if (!l) {
6784     orig->next = dm->labels;
6785     dm->labels = orig;
6786   } else {
6787     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next);
6788     orig->next = prev->next;
6789     prev->next = orig;
6790   }
6791   PetscFunctionReturn(PETSC_SUCCESS);
6792 }
6793 
6794 /*@
6795   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6796 
6797   Not Collective
6798 
6799   Input Parameters:
6800 + dm    - The `DM` object
6801 . name  - The label name
6802 - point - The mesh point
6803 
6804   Output Parameter:
6805 . value - The label value for this point, or -1 if the point is not in the label
6806 
6807   Level: beginner
6808 
6809 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6810 @*/
6811 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6812 {
6813   DMLabel label;
6814 
6815   PetscFunctionBegin;
6816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6817   PetscAssertPointer(name, 2);
6818   PetscCall(DMGetLabel(dm, name, &label));
6819   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6820   PetscCall(DMLabelGetValue(label, point, value));
6821   PetscFunctionReturn(PETSC_SUCCESS);
6822 }
6823 
6824 /*@
6825   DMSetLabelValue - Add a point to a `DMLabel` with given value
6826 
6827   Not Collective
6828 
6829   Input Parameters:
6830 + dm    - The `DM` object
6831 . name  - The label name
6832 . point - The mesh point
6833 - value - The label value for this point
6834 
6835   Output Parameter:
6836 
6837   Level: beginner
6838 
6839 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6840 @*/
6841 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6842 {
6843   DMLabel label;
6844 
6845   PetscFunctionBegin;
6846   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6847   PetscAssertPointer(name, 2);
6848   PetscCall(DMGetLabel(dm, name, &label));
6849   if (!label) {
6850     PetscCall(DMCreateLabel(dm, name));
6851     PetscCall(DMGetLabel(dm, name, &label));
6852   }
6853   PetscCall(DMLabelSetValue(label, point, value));
6854   PetscFunctionReturn(PETSC_SUCCESS);
6855 }
6856 
6857 /*@
6858   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6859 
6860   Not Collective
6861 
6862   Input Parameters:
6863 + dm    - The `DM` object
6864 . name  - The label name
6865 . point - The mesh point
6866 - value - The label value for this point
6867 
6868   Level: beginner
6869 
6870 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6871 @*/
6872 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6873 {
6874   DMLabel label;
6875 
6876   PetscFunctionBegin;
6877   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6878   PetscAssertPointer(name, 2);
6879   PetscCall(DMGetLabel(dm, name, &label));
6880   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6881   PetscCall(DMLabelClearValue(label, point, value));
6882   PetscFunctionReturn(PETSC_SUCCESS);
6883 }
6884 
6885 /*@
6886   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6887 
6888   Not Collective
6889 
6890   Input Parameters:
6891 + dm   - The `DM` object
6892 - name - The label name
6893 
6894   Output Parameter:
6895 . size - The number of different integer ids, or 0 if the label does not exist
6896 
6897   Level: beginner
6898 
6899   Developer Note:
6900   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6901 
6902 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6903 @*/
6904 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6905 {
6906   DMLabel label;
6907 
6908   PetscFunctionBegin;
6909   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6910   PetscAssertPointer(name, 2);
6911   PetscAssertPointer(size, 3);
6912   PetscCall(DMGetLabel(dm, name, &label));
6913   *size = 0;
6914   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6915   PetscCall(DMLabelGetNumValues(label, size));
6916   PetscFunctionReturn(PETSC_SUCCESS);
6917 }
6918 
6919 /*@
6920   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6921 
6922   Not Collective
6923 
6924   Input Parameters:
6925 + dm   - The `DM` object
6926 - name - The label name
6927 
6928   Output Parameter:
6929 . ids - The integer ids, or `NULL` if the label does not exist
6930 
6931   Level: beginner
6932 
6933 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6934 @*/
6935 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6936 {
6937   DMLabel label;
6938 
6939   PetscFunctionBegin;
6940   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6941   PetscAssertPointer(name, 2);
6942   PetscAssertPointer(ids, 3);
6943   PetscCall(DMGetLabel(dm, name, &label));
6944   *ids = NULL;
6945   if (label) {
6946     PetscCall(DMLabelGetValueIS(label, ids));
6947   } else {
6948     /* returning an empty IS */
6949     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6950   }
6951   PetscFunctionReturn(PETSC_SUCCESS);
6952 }
6953 
6954 /*@
6955   DMGetStratumSize - Get the number of points in a label stratum
6956 
6957   Not Collective
6958 
6959   Input Parameters:
6960 + dm    - The `DM` object
6961 . name  - The label name of the stratum
6962 - value - The stratum value
6963 
6964   Output Parameter:
6965 . size - The number of points, also called the stratum size
6966 
6967   Level: beginner
6968 
6969 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6970 @*/
6971 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6972 {
6973   DMLabel label;
6974 
6975   PetscFunctionBegin;
6976   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6977   PetscAssertPointer(name, 2);
6978   PetscAssertPointer(size, 4);
6979   PetscCall(DMGetLabel(dm, name, &label));
6980   *size = 0;
6981   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6982   PetscCall(DMLabelGetStratumSize(label, value, size));
6983   PetscFunctionReturn(PETSC_SUCCESS);
6984 }
6985 
6986 /*@
6987   DMGetStratumIS - Get the points in a label stratum
6988 
6989   Not Collective
6990 
6991   Input Parameters:
6992 + dm    - The `DM` object
6993 . name  - The label name
6994 - value - The stratum value
6995 
6996   Output Parameter:
6997 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
6998 
6999   Level: beginner
7000 
7001 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
7002 @*/
7003 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7004 {
7005   DMLabel label;
7006 
7007   PetscFunctionBegin;
7008   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7009   PetscAssertPointer(name, 2);
7010   PetscAssertPointer(points, 4);
7011   PetscCall(DMGetLabel(dm, name, &label));
7012   *points = NULL;
7013   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7014   PetscCall(DMLabelGetStratumIS(label, value, points));
7015   PetscFunctionReturn(PETSC_SUCCESS);
7016 }
7017 
7018 /*@
7019   DMSetStratumIS - Set the points in a label stratum
7020 
7021   Not Collective
7022 
7023   Input Parameters:
7024 + dm     - The `DM` object
7025 . name   - The label name
7026 . value  - The stratum value
7027 - points - The stratum points
7028 
7029   Level: beginner
7030 
7031 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
7032 @*/
7033 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7034 {
7035   DMLabel label;
7036 
7037   PetscFunctionBegin;
7038   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7039   PetscAssertPointer(name, 2);
7040   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
7041   PetscCall(DMGetLabel(dm, name, &label));
7042   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7043   PetscCall(DMLabelSetStratumIS(label, value, points));
7044   PetscFunctionReturn(PETSC_SUCCESS);
7045 }
7046 
7047 /*@
7048   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
7049 
7050   Not Collective
7051 
7052   Input Parameters:
7053 + dm    - The `DM` object
7054 . name  - The label name
7055 - value - The label value for this point
7056 
7057   Output Parameter:
7058 
7059   Level: beginner
7060 
7061 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7062 @*/
7063 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7064 {
7065   DMLabel label;
7066 
7067   PetscFunctionBegin;
7068   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7069   PetscAssertPointer(name, 2);
7070   PetscCall(DMGetLabel(dm, name, &label));
7071   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7072   PetscCall(DMLabelClearStratum(label, value));
7073   PetscFunctionReturn(PETSC_SUCCESS);
7074 }
7075 
7076 /*@
7077   DMGetNumLabels - Return the number of labels defined by on the `DM`
7078 
7079   Not Collective
7080 
7081   Input Parameter:
7082 . dm - The `DM` object
7083 
7084   Output Parameter:
7085 . numLabels - the number of Labels
7086 
7087   Level: intermediate
7088 
7089 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7090 @*/
7091 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7092 {
7093   DMLabelLink next = dm->labels;
7094   PetscInt    n    = 0;
7095 
7096   PetscFunctionBegin;
7097   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7098   PetscAssertPointer(numLabels, 2);
7099   while (next) {
7100     ++n;
7101     next = next->next;
7102   }
7103   *numLabels = n;
7104   PetscFunctionReturn(PETSC_SUCCESS);
7105 }
7106 
7107 /*@
7108   DMGetLabelName - Return the name of nth label
7109 
7110   Not Collective
7111 
7112   Input Parameters:
7113 + dm - The `DM` object
7114 - n  - the label number
7115 
7116   Output Parameter:
7117 . name - the label name
7118 
7119   Level: intermediate
7120 
7121   Developer Note:
7122   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
7123 
7124 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7125 @*/
7126 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[])
7127 {
7128   DMLabelLink next = dm->labels;
7129   PetscInt    l    = 0;
7130 
7131   PetscFunctionBegin;
7132   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7133   PetscAssertPointer(name, 3);
7134   while (next) {
7135     if (l == n) {
7136       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
7137       PetscFunctionReturn(PETSC_SUCCESS);
7138     }
7139     ++l;
7140     next = next->next;
7141   }
7142   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7143 }
7144 
7145 /*@
7146   DMHasLabel - Determine whether the `DM` has a label of a given name
7147 
7148   Not Collective
7149 
7150   Input Parameters:
7151 + dm   - The `DM` object
7152 - name - The label name
7153 
7154   Output Parameter:
7155 . hasLabel - `PETSC_TRUE` if the label is present
7156 
7157   Level: intermediate
7158 
7159 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7160 @*/
7161 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7162 {
7163   DMLabelLink next = dm->labels;
7164   const char *lname;
7165 
7166   PetscFunctionBegin;
7167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7168   PetscAssertPointer(name, 2);
7169   PetscAssertPointer(hasLabel, 3);
7170   *hasLabel = PETSC_FALSE;
7171   while (next) {
7172     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7173     PetscCall(PetscStrcmp(name, lname, hasLabel));
7174     if (*hasLabel) break;
7175     next = next->next;
7176   }
7177   PetscFunctionReturn(PETSC_SUCCESS);
7178 }
7179 
7180 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7181 /*@
7182   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
7183 
7184   Not Collective
7185 
7186   Input Parameters:
7187 + dm   - The `DM` object
7188 - name - The label name
7189 
7190   Output Parameter:
7191 . label - The `DMLabel`, or `NULL` if the label is absent
7192 
7193   Default labels in a `DMPLEX`:
7194 + "depth"       - Holds the depth (co-dimension) of each mesh point
7195 . "celltype"    - Holds the topological type of each cell
7196 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7197 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7198 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7199 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7200 
7201   Level: intermediate
7202 
7203 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7204 @*/
7205 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7206 {
7207   DMLabelLink next = dm->labels;
7208   PetscBool   hasLabel;
7209   const char *lname;
7210 
7211   PetscFunctionBegin;
7212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7213   PetscAssertPointer(name, 2);
7214   PetscAssertPointer(label, 3);
7215   *label = NULL;
7216   while (next) {
7217     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7218     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7219     if (hasLabel) {
7220       *label = next->label;
7221       break;
7222     }
7223     next = next->next;
7224   }
7225   PetscFunctionReturn(PETSC_SUCCESS);
7226 }
7227 
7228 /*@
7229   DMGetLabelByNum - Return the nth label on a `DM`
7230 
7231   Not Collective
7232 
7233   Input Parameters:
7234 + dm - The `DM` object
7235 - n  - the label number
7236 
7237   Output Parameter:
7238 . label - the label
7239 
7240   Level: intermediate
7241 
7242 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7243 @*/
7244 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7245 {
7246   DMLabelLink next = dm->labels;
7247   PetscInt    l    = 0;
7248 
7249   PetscFunctionBegin;
7250   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7251   PetscAssertPointer(label, 3);
7252   while (next) {
7253     if (l == n) {
7254       *label = next->label;
7255       PetscFunctionReturn(PETSC_SUCCESS);
7256     }
7257     ++l;
7258     next = next->next;
7259   }
7260   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7261 }
7262 
7263 /*@
7264   DMAddLabel - Add the label to this `DM`
7265 
7266   Not Collective
7267 
7268   Input Parameters:
7269 + dm    - The `DM` object
7270 - label - The `DMLabel`
7271 
7272   Level: developer
7273 
7274 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7275 @*/
7276 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7277 {
7278   DMLabelLink l, *p, tmpLabel;
7279   PetscBool   hasLabel;
7280   const char *lname;
7281   PetscBool   flg;
7282 
7283   PetscFunctionBegin;
7284   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7285   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7286   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7287   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7288   PetscCall(PetscCalloc1(1, &tmpLabel));
7289   tmpLabel->label  = label;
7290   tmpLabel->output = PETSC_TRUE;
7291   for (p = &dm->labels; (l = *p); p = &l->next) { }
7292   *p = tmpLabel;
7293   PetscCall(PetscObjectReference((PetscObject)label));
7294   PetscCall(PetscStrcmp(lname, "depth", &flg));
7295   if (flg) dm->depthLabel = label;
7296   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7297   if (flg) dm->celltypeLabel = label;
7298   PetscFunctionReturn(PETSC_SUCCESS);
7299 }
7300 
7301 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7302 /*@
7303   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7304 
7305   Not Collective
7306 
7307   Input Parameters:
7308 + dm    - The `DM` object
7309 - label - The `DMLabel`, having the same name, to substitute
7310 
7311   Default labels in a `DMPLEX`:
7312 + "depth"       - Holds the depth (co-dimension) of each mesh point
7313 . "celltype"    - Holds the topological type of each cell
7314 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7315 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7316 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7317 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7318 
7319   Level: intermediate
7320 
7321 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7322 @*/
7323 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7324 {
7325   DMLabelLink next = dm->labels;
7326   PetscBool   hasLabel, flg;
7327   const char *name, *lname;
7328 
7329   PetscFunctionBegin;
7330   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7331   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7332   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7333   while (next) {
7334     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7335     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7336     if (hasLabel) {
7337       PetscCall(PetscObjectReference((PetscObject)label));
7338       PetscCall(PetscStrcmp(lname, "depth", &flg));
7339       if (flg) dm->depthLabel = label;
7340       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7341       if (flg) dm->celltypeLabel = label;
7342       PetscCall(DMLabelDestroy(&next->label));
7343       next->label = label;
7344       break;
7345     }
7346     next = next->next;
7347   }
7348   PetscFunctionReturn(PETSC_SUCCESS);
7349 }
7350 
7351 /*@
7352   DMRemoveLabel - Remove the label given by name from this `DM`
7353 
7354   Not Collective
7355 
7356   Input Parameters:
7357 + dm   - The `DM` object
7358 - name - The label name
7359 
7360   Output Parameter:
7361 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7362           caller is responsible for calling `DMLabelDestroy()`.
7363 
7364   Level: developer
7365 
7366 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7367 @*/
7368 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7369 {
7370   DMLabelLink link, *pnext;
7371   PetscBool   hasLabel;
7372   const char *lname;
7373 
7374   PetscFunctionBegin;
7375   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7376   PetscAssertPointer(name, 2);
7377   if (label) {
7378     PetscAssertPointer(label, 3);
7379     *label = NULL;
7380   }
7381   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7382     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7383     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7384     if (hasLabel) {
7385       *pnext = link->next; /* Remove from list */
7386       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7387       if (hasLabel) dm->depthLabel = NULL;
7388       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7389       if (hasLabel) dm->celltypeLabel = NULL;
7390       if (label) *label = link->label;
7391       else PetscCall(DMLabelDestroy(&link->label));
7392       PetscCall(PetscFree(link));
7393       break;
7394     }
7395   }
7396   PetscFunctionReturn(PETSC_SUCCESS);
7397 }
7398 
7399 /*@
7400   DMRemoveLabelBySelf - Remove the label from this `DM`
7401 
7402   Not Collective
7403 
7404   Input Parameters:
7405 + dm           - The `DM` object
7406 . label        - The `DMLabel` to be removed from the `DM`
7407 - failNotFound - Should it fail if the label is not found in the `DM`?
7408 
7409   Level: developer
7410 
7411   Note:
7412   Only exactly the same instance is removed if found, name match is ignored.
7413   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7414   *label nullified.
7415 
7416 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7417 @*/
7418 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7419 {
7420   DMLabelLink link, *pnext;
7421   PetscBool   hasLabel = PETSC_FALSE;
7422 
7423   PetscFunctionBegin;
7424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7425   PetscAssertPointer(label, 2);
7426   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7427   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7428   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7429   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7430     if (*label == link->label) {
7431       hasLabel = PETSC_TRUE;
7432       *pnext   = link->next; /* Remove from list */
7433       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7434       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7435       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7436       PetscCall(DMLabelDestroy(&link->label));
7437       PetscCall(PetscFree(link));
7438       break;
7439     }
7440   }
7441   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7442   PetscFunctionReturn(PETSC_SUCCESS);
7443 }
7444 
7445 /*@
7446   DMGetLabelOutput - Get the output flag for a given label
7447 
7448   Not Collective
7449 
7450   Input Parameters:
7451 + dm   - The `DM` object
7452 - name - The label name
7453 
7454   Output Parameter:
7455 . output - The flag for output
7456 
7457   Level: developer
7458 
7459 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7460 @*/
7461 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7462 {
7463   DMLabelLink next = dm->labels;
7464   const char *lname;
7465 
7466   PetscFunctionBegin;
7467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7468   PetscAssertPointer(name, 2);
7469   PetscAssertPointer(output, 3);
7470   while (next) {
7471     PetscBool flg;
7472 
7473     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7474     PetscCall(PetscStrcmp(name, lname, &flg));
7475     if (flg) {
7476       *output = next->output;
7477       PetscFunctionReturn(PETSC_SUCCESS);
7478     }
7479     next = next->next;
7480   }
7481   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7482 }
7483 
7484 /*@
7485   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7486 
7487   Not Collective
7488 
7489   Input Parameters:
7490 + dm     - The `DM` object
7491 . name   - The label name
7492 - output - `PETSC_TRUE` to save the label to the viewer
7493 
7494   Level: developer
7495 
7496 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7497 @*/
7498 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7499 {
7500   DMLabelLink next = dm->labels;
7501   const char *lname;
7502 
7503   PetscFunctionBegin;
7504   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7505   PetscAssertPointer(name, 2);
7506   while (next) {
7507     PetscBool flg;
7508 
7509     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7510     PetscCall(PetscStrcmp(name, lname, &flg));
7511     if (flg) {
7512       next->output = output;
7513       PetscFunctionReturn(PETSC_SUCCESS);
7514     }
7515     next = next->next;
7516   }
7517   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7518 }
7519 
7520 /*@
7521   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7522 
7523   Collective
7524 
7525   Input Parameters:
7526 + dmA   - The `DM` object with initial labels
7527 . dmB   - The `DM` object to which labels are copied
7528 . mode  - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7529 . all   - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7530 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7531 
7532   Level: intermediate
7533 
7534   Note:
7535   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7536 
7537 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7538 @*/
7539 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7540 {
7541   DMLabel     label, labelNew, labelOld;
7542   const char *name;
7543   PetscBool   flg;
7544   DMLabelLink link;
7545 
7546   PetscFunctionBegin;
7547   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7548   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7549   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7550   PetscValidLogicalCollectiveBool(dmA, all, 4);
7551   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7552   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7553   for (link = dmA->labels; link; link = link->next) {
7554     label = link->label;
7555     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7556     if (!all) {
7557       PetscCall(PetscStrcmp(name, "depth", &flg));
7558       if (flg) continue;
7559       PetscCall(PetscStrcmp(name, "dim", &flg));
7560       if (flg) continue;
7561       PetscCall(PetscStrcmp(name, "celltype", &flg));
7562       if (flg) continue;
7563     }
7564     PetscCall(DMGetLabel(dmB, name, &labelOld));
7565     if (labelOld) {
7566       switch (emode) {
7567       case DM_COPY_LABELS_KEEP:
7568         continue;
7569       case DM_COPY_LABELS_REPLACE:
7570         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7571         break;
7572       case DM_COPY_LABELS_FAIL:
7573         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7574       default:
7575         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7576       }
7577     }
7578     if (mode == PETSC_COPY_VALUES) {
7579       PetscCall(DMLabelDuplicate(label, &labelNew));
7580     } else {
7581       labelNew = label;
7582     }
7583     PetscCall(DMAddLabel(dmB, labelNew));
7584     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7585   }
7586   PetscFunctionReturn(PETSC_SUCCESS);
7587 }
7588 
7589 /*@C
7590   DMCompareLabels - Compare labels between two `DM` objects
7591 
7592   Collective; No Fortran Support
7593 
7594   Input Parameters:
7595 + dm0 - First `DM` object
7596 - dm1 - Second `DM` object
7597 
7598   Output Parameters:
7599 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7600 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7601 
7602   Level: intermediate
7603 
7604   Notes:
7605   The output flag equal will be the same on all processes.
7606 
7607   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7608 
7609   Make sure to pass equal is `NULL` on all processes or none of them.
7610 
7611   The output message is set independently on each rank.
7612 
7613   message must be freed with `PetscFree()`
7614 
7615   If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner.
7616 
7617   Make sure to pass message as `NULL` on all processes or no processes.
7618 
7619   Labels are matched by name. If the number of labels and their names are equal,
7620   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7621 
7622   Developer Note:
7623   Can automatically generate the Fortran stub because `message` must be freed with `PetscFree()`
7624 
7625 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7626 @*/
7627 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7628 {
7629   PetscInt    n, i;
7630   char        msg[PETSC_MAX_PATH_LEN] = "";
7631   PetscBool   eq;
7632   MPI_Comm    comm;
7633   PetscMPIInt rank;
7634 
7635   PetscFunctionBegin;
7636   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7637   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7638   PetscCheckSameComm(dm0, 1, dm1, 2);
7639   if (equal) PetscAssertPointer(equal, 3);
7640   if (message) PetscAssertPointer(message, 4);
7641   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7642   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7643   {
7644     PetscInt n1;
7645 
7646     PetscCall(DMGetNumLabels(dm0, &n));
7647     PetscCall(DMGetNumLabels(dm1, &n1));
7648     eq = (PetscBool)(n == n1);
7649     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7650     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7651     if (!eq) goto finish;
7652   }
7653   for (i = 0; i < n; i++) {
7654     DMLabel     l0, l1;
7655     const char *name;
7656     char       *msgInner;
7657 
7658     /* Ignore label order */
7659     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7660     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7661     PetscCall(DMGetLabel(dm1, name, &l1));
7662     if (!l1) {
7663       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7664       eq = PETSC_FALSE;
7665       break;
7666     }
7667     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7668     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7669     PetscCall(PetscFree(msgInner));
7670     if (!eq) break;
7671   }
7672   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7673 finish:
7674   /* If message output arg not set, print to stderr */
7675   if (message) {
7676     *message = NULL;
7677     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7678   } else {
7679     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7680     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7681   }
7682   /* If same output arg not ser and labels are not equal, throw error */
7683   if (equal) *equal = eq;
7684   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7685   PetscFunctionReturn(PETSC_SUCCESS);
7686 }
7687 
7688 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7689 {
7690   PetscFunctionBegin;
7691   PetscAssertPointer(label, 2);
7692   if (!*label) {
7693     PetscCall(DMCreateLabel(dm, name));
7694     PetscCall(DMGetLabel(dm, name, label));
7695   }
7696   PetscCall(DMLabelSetValue(*label, point, value));
7697   PetscFunctionReturn(PETSC_SUCCESS);
7698 }
7699 
7700 /*
7701   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7702   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7703   (label, id) pair in the DM.
7704 
7705   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7706   each label.
7707 */
7708 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7709 {
7710   DMUniversalLabel ul;
7711   PetscBool       *active;
7712   PetscInt         pStart, pEnd, p, Nl, l, m;
7713 
7714   PetscFunctionBegin;
7715   PetscCall(PetscMalloc1(1, &ul));
7716   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7717   PetscCall(DMGetNumLabels(dm, &Nl));
7718   PetscCall(PetscCalloc1(Nl, &active));
7719   ul->Nl = 0;
7720   for (l = 0; l < Nl; ++l) {
7721     PetscBool   isdepth, iscelltype;
7722     const char *name;
7723 
7724     PetscCall(DMGetLabelName(dm, l, &name));
7725     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7726     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7727     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7728     if (active[l]) ++ul->Nl;
7729   }
7730   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7731   ul->Nv = 0;
7732   for (l = 0, m = 0; l < Nl; ++l) {
7733     DMLabel     label;
7734     PetscInt    nv;
7735     const char *name;
7736 
7737     if (!active[l]) continue;
7738     PetscCall(DMGetLabelName(dm, l, &name));
7739     PetscCall(DMGetLabelByNum(dm, l, &label));
7740     PetscCall(DMLabelGetNumValues(label, &nv));
7741     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7742     ul->indices[m] = l;
7743     ul->Nv += nv;
7744     ul->offsets[m + 1] = nv;
7745     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7746     ++m;
7747   }
7748   for (l = 1; l <= ul->Nl; ++l) {
7749     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7750     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7751   }
7752   for (l = 0; l < ul->Nl; ++l) {
7753     PetscInt b;
7754 
7755     ul->masks[l] = 0;
7756     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7757   }
7758   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7759   for (l = 0, m = 0; l < Nl; ++l) {
7760     DMLabel         label;
7761     IS              valueIS;
7762     const PetscInt *varr;
7763     PetscInt        nv, v;
7764 
7765     if (!active[l]) continue;
7766     PetscCall(DMGetLabelByNum(dm, l, &label));
7767     PetscCall(DMLabelGetNumValues(label, &nv));
7768     PetscCall(DMLabelGetValueIS(label, &valueIS));
7769     PetscCall(ISGetIndices(valueIS, &varr));
7770     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7771     PetscCall(ISRestoreIndices(valueIS, &varr));
7772     PetscCall(ISDestroy(&valueIS));
7773     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7774     ++m;
7775   }
7776   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7777   for (p = pStart; p < pEnd; ++p) {
7778     PetscInt  uval   = 0;
7779     PetscBool marked = PETSC_FALSE;
7780 
7781     for (l = 0, m = 0; l < Nl; ++l) {
7782       DMLabel  label;
7783       PetscInt val, defval, loc, nv;
7784 
7785       if (!active[l]) continue;
7786       PetscCall(DMGetLabelByNum(dm, l, &label));
7787       PetscCall(DMLabelGetValue(label, p, &val));
7788       PetscCall(DMLabelGetDefaultValue(label, &defval));
7789       if (val == defval) {
7790         ++m;
7791         continue;
7792       }
7793       nv     = ul->offsets[m + 1] - ul->offsets[m];
7794       marked = PETSC_TRUE;
7795       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7796       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7797       uval += (loc + 1) << ul->bits[m];
7798       ++m;
7799     }
7800     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7801   }
7802   PetscCall(PetscFree(active));
7803   *universal = ul;
7804   PetscFunctionReturn(PETSC_SUCCESS);
7805 }
7806 
7807 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7808 {
7809   PetscInt l;
7810 
7811   PetscFunctionBegin;
7812   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7813   PetscCall(DMLabelDestroy(&(*universal)->label));
7814   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7815   PetscCall(PetscFree((*universal)->values));
7816   PetscCall(PetscFree(*universal));
7817   *universal = NULL;
7818   PetscFunctionReturn(PETSC_SUCCESS);
7819 }
7820 
7821 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7822 {
7823   PetscFunctionBegin;
7824   PetscAssertPointer(ulabel, 2);
7825   *ulabel = ul->label;
7826   PetscFunctionReturn(PETSC_SUCCESS);
7827 }
7828 
7829 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7830 {
7831   PetscInt Nl = ul->Nl, l;
7832 
7833   PetscFunctionBegin;
7834   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7835   for (l = 0; l < Nl; ++l) {
7836     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7837     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7838   }
7839   if (preserveOrder) {
7840     for (l = 0; l < ul->Nl; ++l) {
7841       const char *name;
7842       PetscBool   match;
7843 
7844       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7845       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7846       PetscCheck(match, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Label %" PetscInt_FMT " name %s does not match new name %s", l, name, ul->names[l]);
7847     }
7848   }
7849   PetscFunctionReturn(PETSC_SUCCESS);
7850 }
7851 
7852 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7853 {
7854   PetscInt l;
7855 
7856   PetscFunctionBegin;
7857   for (l = 0; l < ul->Nl; ++l) {
7858     DMLabel  label;
7859     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7860 
7861     if (lval) {
7862       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7863       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7864       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7865     }
7866   }
7867   PetscFunctionReturn(PETSC_SUCCESS);
7868 }
7869 
7870 /*@
7871   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7872 
7873   Not Collective
7874 
7875   Input Parameter:
7876 . dm - The `DM` object
7877 
7878   Output Parameter:
7879 . cdm - The coarse `DM`
7880 
7881   Level: intermediate
7882 
7883 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7884 @*/
7885 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7886 {
7887   PetscFunctionBegin;
7888   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7889   PetscAssertPointer(cdm, 2);
7890   *cdm = dm->coarseMesh;
7891   PetscFunctionReturn(PETSC_SUCCESS);
7892 }
7893 
7894 /*@
7895   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7896 
7897   Input Parameters:
7898 + dm  - The `DM` object
7899 - cdm - The coarse `DM`
7900 
7901   Level: intermediate
7902 
7903   Note:
7904   Normally this is set automatically by `DMRefine()`
7905 
7906 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7907 @*/
7908 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7909 {
7910   PetscFunctionBegin;
7911   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7912   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7913   if (dm == cdm) cdm = NULL;
7914   PetscCall(PetscObjectReference((PetscObject)cdm));
7915   PetscCall(DMDestroy(&dm->coarseMesh));
7916   dm->coarseMesh = cdm;
7917   PetscFunctionReturn(PETSC_SUCCESS);
7918 }
7919 
7920 /*@
7921   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7922 
7923   Input Parameter:
7924 . dm - The `DM` object
7925 
7926   Output Parameter:
7927 . fdm - The fine `DM`
7928 
7929   Level: intermediate
7930 
7931 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7932 @*/
7933 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7934 {
7935   PetscFunctionBegin;
7936   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7937   PetscAssertPointer(fdm, 2);
7938   *fdm = dm->fineMesh;
7939   PetscFunctionReturn(PETSC_SUCCESS);
7940 }
7941 
7942 /*@
7943   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7944 
7945   Input Parameters:
7946 + dm  - The `DM` object
7947 - fdm - The fine `DM`
7948 
7949   Level: developer
7950 
7951   Note:
7952   Normally this is set automatically by `DMCoarsen()`
7953 
7954 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7955 @*/
7956 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7957 {
7958   PetscFunctionBegin;
7959   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7960   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7961   if (dm == fdm) fdm = NULL;
7962   PetscCall(PetscObjectReference((PetscObject)fdm));
7963   PetscCall(DMDestroy(&dm->fineMesh));
7964   dm->fineMesh = fdm;
7965   PetscFunctionReturn(PETSC_SUCCESS);
7966 }
7967 
7968 /*@C
7969   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7970 
7971   Collective
7972 
7973   Input Parameters:
7974 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7975 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7976 . name     - The BC name
7977 . label    - The label defining constrained points
7978 . Nv       - The number of `DMLabel` values for constrained points
7979 . values   - An array of values for constrained points
7980 . field    - The field to constrain
7981 . Nc       - The number of constrained field components (0 will constrain all fields)
7982 . comps    - An array of constrained component numbers
7983 . bcFunc   - A pointwise function giving boundary values
7984 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7985 - ctx      - An optional user context for bcFunc
7986 
7987   Output Parameter:
7988 . bd - (Optional) Boundary number
7989 
7990   Options Database Keys:
7991 + -bc_<boundary name> <num>      - Overrides the boundary ids
7992 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7993 
7994   Level: intermediate
7995 
7996   Notes:
7997   Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
7998 .vb
7999  void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8000 .ve
8001 
8002   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
8003 
8004 .vb
8005   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8006               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8007               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8008               PetscReal time, const PetscReal x[], PetscScalar bcval[])
8009 .ve
8010 + dim - the spatial dimension
8011 . Nf - the number of fields
8012 . uOff - the offset into u[] and u_t[] for each field
8013 . uOff_x - the offset into u_x[] for each field
8014 . u - each field evaluated at the current point
8015 . u_t - the time derivative of each field evaluated at the current point
8016 . u_x - the gradient of each field evaluated at the current point
8017 . aOff - the offset into a[] and a_t[] for each auxiliary field
8018 . aOff_x - the offset into a_x[] for each auxiliary field
8019 . a - each auxiliary field evaluated at the current point
8020 . a_t - the time derivative of each auxiliary field evaluated at the current point
8021 . a_x - the gradient of auxiliary each field evaluated at the current point
8022 . t - current time
8023 . x - coordinates of the current point
8024 . numConstants - number of constant parameters
8025 . constants - constant parameters
8026 - bcval - output values at the current point
8027 
8028 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
8029 @*/
8030 PetscErrorCode DMAddBoundary(DM dm, DMBoundaryConditionType type, const char name[], DMLabel label, PetscInt Nv, const PetscInt values[], PetscInt field, PetscInt Nc, const PetscInt comps[], void (*bcFunc)(void), void (*bcFunc_t)(void), void *ctx, PetscInt *bd)
8031 {
8032   PetscDS ds;
8033 
8034   PetscFunctionBegin;
8035   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8036   PetscValidLogicalCollectiveEnum(dm, type, 2);
8037   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8038   PetscValidLogicalCollectiveInt(dm, Nv, 5);
8039   PetscValidLogicalCollectiveInt(dm, field, 7);
8040   PetscValidLogicalCollectiveInt(dm, Nc, 8);
8041   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
8042   PetscCall(DMGetDS(dm, &ds));
8043   /* Complete label */
8044   if (label) {
8045     PetscObject  obj;
8046     PetscClassId id;
8047 
8048     PetscCall(DMGetField(dm, field, NULL, &obj));
8049     PetscCall(PetscObjectGetClassId(obj, &id));
8050     if (id == PETSCFE_CLASSID) {
8051       DM plex;
8052 
8053       PetscCall(DMConvert(dm, DMPLEX, &plex));
8054       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8055       PetscCall(DMDestroy(&plex));
8056     }
8057   }
8058   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8059   PetscFunctionReturn(PETSC_SUCCESS);
8060 }
8061 
8062 /* TODO Remove this since now the structures are the same */
8063 static PetscErrorCode DMPopulateBoundary(DM dm)
8064 {
8065   PetscDS     ds;
8066   DMBoundary *lastnext;
8067   DSBoundary  dsbound;
8068 
8069   PetscFunctionBegin;
8070   PetscCall(DMGetDS(dm, &ds));
8071   dsbound = ds->boundary;
8072   if (dm->boundary) {
8073     DMBoundary next = dm->boundary;
8074 
8075     /* quick check to see if the PetscDS has changed */
8076     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
8077     /* the PetscDS has changed: tear down and rebuild */
8078     while (next) {
8079       DMBoundary b = next;
8080 
8081       next = b->next;
8082       PetscCall(PetscFree(b));
8083     }
8084     dm->boundary = NULL;
8085   }
8086 
8087   lastnext = &dm->boundary;
8088   while (dsbound) {
8089     DMBoundary dmbound;
8090 
8091     PetscCall(PetscNew(&dmbound));
8092     dmbound->dsboundary = dsbound;
8093     dmbound->label      = dsbound->label;
8094     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8095     *lastnext = dmbound;
8096     lastnext  = &dmbound->next;
8097     dsbound   = dsbound->next;
8098   }
8099   PetscFunctionReturn(PETSC_SUCCESS);
8100 }
8101 
8102 /* TODO: missing manual page */
8103 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8104 {
8105   DMBoundary b;
8106 
8107   PetscFunctionBegin;
8108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8109   PetscAssertPointer(isBd, 3);
8110   *isBd = PETSC_FALSE;
8111   PetscCall(DMPopulateBoundary(dm));
8112   b = dm->boundary;
8113   while (b && !*isBd) {
8114     DMLabel    label = b->label;
8115     DSBoundary dsb   = b->dsboundary;
8116     PetscInt   i;
8117 
8118     if (label) {
8119       for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8120     }
8121     b = b->next;
8122   }
8123   PetscFunctionReturn(PETSC_SUCCESS);
8124 }
8125 
8126 /*@C
8127   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
8128 
8129   Collective
8130 
8131   Input Parameters:
8132 + dm    - The `DM`
8133 . time  - The time
8134 . funcs - The coordinate functions to evaluate, one per field
8135 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8136 - mode  - The insertion mode for values
8137 
8138   Output Parameter:
8139 . X - vector
8140 
8141   Calling sequence of `funcs`:
8142 + dim  - The spatial dimension
8143 . time - The time at which to sample
8144 . x    - The coordinates
8145 . Nc   - The number of components
8146 . u    - The output field values
8147 - ctx  - optional user-defined function context
8148 
8149   Level: developer
8150 
8151   Developer Notes:
8152   This API is specific to only particular usage of `DM`
8153 
8154   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8155 
8156 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8157 @*/
8158 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx), void **ctxs, InsertMode mode, Vec X)
8159 {
8160   Vec localX;
8161 
8162   PetscFunctionBegin;
8163   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8164   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
8165   PetscCall(DMGetLocalVector(dm, &localX));
8166   PetscCall(VecSet(localX, 0.));
8167   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8168   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8169   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8170   PetscCall(DMRestoreLocalVector(dm, &localX));
8171   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
8172   PetscFunctionReturn(PETSC_SUCCESS);
8173 }
8174 
8175 /*@C
8176   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
8177 
8178   Not Collective
8179 
8180   Input Parameters:
8181 + dm    - The `DM`
8182 . time  - The time
8183 . funcs - The coordinate functions to evaluate, one per field
8184 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8185 - mode  - The insertion mode for values
8186 
8187   Output Parameter:
8188 . localX - vector
8189 
8190   Calling sequence of `funcs`:
8191 + dim  - The spatial dimension
8192 . time - The current timestep
8193 . x    - The coordinates
8194 . Nc   - The number of components
8195 . u    - The output field values
8196 - ctx  - optional user-defined function context
8197 
8198   Level: developer
8199 
8200   Developer Notes:
8201   This API is specific to only particular usage of `DM`
8202 
8203   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8204 
8205 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8206 @*/
8207 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx), void **ctxs, InsertMode mode, Vec localX)
8208 {
8209   PetscFunctionBegin;
8210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8211   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8212   PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX);
8213   PetscFunctionReturn(PETSC_SUCCESS);
8214 }
8215 
8216 /*@C
8217   DMProjectFunctionLabel - This projects the given function into the function space provided by the `DM`, putting the coefficients in a global vector, setting values only for points in the given label.
8218 
8219   Collective
8220 
8221   Input Parameters:
8222 + dm     - The `DM`
8223 . time   - The time
8224 . numIds - The number of ids
8225 . ids    - The ids
8226 . Nc     - The number of components
8227 . comps  - The components
8228 . label  - The `DMLabel` selecting the portion of the mesh for projection
8229 . funcs  - The coordinate functions to evaluate, one per field
8230 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8231 - mode   - The insertion mode for values
8232 
8233   Output Parameter:
8234 . X - vector
8235 
8236   Calling sequence of `funcs`:
8237 + dim  - The spatial dimension
8238 . time - The current timestep
8239 . x    - The coordinates
8240 . Nc   - The number of components
8241 . u    - The output field values
8242 - ctx  - optional user-defined function context
8243 
8244   Level: developer
8245 
8246   Developer Notes:
8247   This API is specific to only particular usage of `DM`
8248 
8249   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8250 
8251 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8252 @*/
8253 PetscErrorCode DMProjectFunctionLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx), void **ctxs, InsertMode mode, Vec X)
8254 {
8255   Vec localX;
8256 
8257   PetscFunctionBegin;
8258   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8259   PetscCall(DMGetLocalVector(dm, &localX));
8260   PetscCall(VecSet(localX, 0.));
8261   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8262   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8263   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8264   PetscCall(DMRestoreLocalVector(dm, &localX));
8265   PetscFunctionReturn(PETSC_SUCCESS);
8266 }
8267 
8268 /*@C
8269   DMProjectFunctionLabelLocal - This projects the given function into the function space provided by the `DM`, putting the coefficients in a local vector, setting values only for points in the given label.
8270 
8271   Not Collective
8272 
8273   Input Parameters:
8274 + dm     - The `DM`
8275 . time   - The time
8276 . label  - The `DMLabel` selecting the portion of the mesh for projection
8277 . numIds - The number of ids
8278 . ids    - The ids
8279 . Nc     - The number of components
8280 . comps  - The components
8281 . funcs  - The coordinate functions to evaluate, one per field
8282 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8283 - mode   - The insertion mode for values
8284 
8285   Output Parameter:
8286 . localX - vector
8287 
8288   Calling sequence of `funcs`:
8289 + dim  - The spatial dimension
8290 . time - The current time
8291 . x    - The coordinates
8292 . Nc   - The number of components
8293 . u    - The output field values
8294 - ctx  - optional user-defined function context
8295 
8296   Level: developer
8297 
8298   Developer Notes:
8299   This API is specific to only particular usage of `DM`
8300 
8301   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8302 
8303 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8304 @*/
8305 PetscErrorCode DMProjectFunctionLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx), void **ctxs, InsertMode mode, Vec localX)
8306 {
8307   PetscFunctionBegin;
8308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8309   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8310   PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8311   PetscFunctionReturn(PETSC_SUCCESS);
8312 }
8313 
8314 /*@C
8315   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided by the `DM`, putting the coefficients in a local vector.
8316 
8317   Not Collective
8318 
8319   Input Parameters:
8320 + dm     - The `DM`
8321 . time   - The time
8322 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8323 . funcs  - The functions to evaluate, one per field
8324 - mode   - The insertion mode for values
8325 
8326   Output Parameter:
8327 . localX - The output vector
8328 
8329   Calling sequence of `funcs`:
8330 + dim          - The spatial dimension
8331 . Nf           - The number of input fields
8332 . NfAux        - The number of input auxiliary fields
8333 . uOff         - The offset of each field in u[]
8334 . uOff_x       - The offset of each field in u_x[]
8335 . u            - The field values at this point in space
8336 . u_t          - The field time derivative at this point in space (or NULL)
8337 . u_x          - The field derivatives at this point in space
8338 . aOff         - The offset of each auxiliary field in u[]
8339 . aOff_x       - The offset of each auxiliary field in u_x[]
8340 . a            - The auxiliary field values at this point in space
8341 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8342 . a_x          - The auxiliary field derivatives at this point in space
8343 . t            - The current time
8344 . x            - The coordinates of this point
8345 . numConstants - The number of constants
8346 . constants    - The value of each constant
8347 - f            - The value of the function at this point in space
8348 
8349   Level: intermediate
8350 
8351   Note:
8352   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8353   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8354   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8355   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8356 
8357   Developer Notes:
8358   This API is specific to only particular usage of `DM`
8359 
8360   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8361 
8362 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8363 `DMProjectFunction()`, `DMComputeL2Diff()`
8364 @*/
8365 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8366 {
8367   PetscFunctionBegin;
8368   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8369   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8370   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8371   PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX);
8372   PetscFunctionReturn(PETSC_SUCCESS);
8373 }
8374 
8375 /*@C
8376   DMProjectFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain specified by the label.
8377 
8378   Not Collective
8379 
8380   Input Parameters:
8381 + dm     - The `DM`
8382 . time   - The time
8383 . label  - The `DMLabel` marking the portion of the domain to output
8384 . numIds - The number of label ids to use
8385 . ids    - The label ids to use for marking
8386 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8387 . comps  - The components to set in the output, or `NULL` for all components
8388 . localU - The input field vector
8389 . funcs  - The functions to evaluate, one per field
8390 - mode   - The insertion mode for values
8391 
8392   Output Parameter:
8393 . localX - The output vector
8394 
8395   Calling sequence of `funcs`:
8396 + dim          - The spatial dimension
8397 . Nf           - The number of input fields
8398 . NfAux        - The number of input auxiliary fields
8399 . uOff         - The offset of each field in u[]
8400 . uOff_x       - The offset of each field in u_x[]
8401 . u            - The field values at this point in space
8402 . u_t          - The field time derivative at this point in space (or NULL)
8403 . u_x          - The field derivatives at this point in space
8404 . aOff         - The offset of each auxiliary field in u[]
8405 . aOff_x       - The offset of each auxiliary field in u_x[]
8406 . a            - The auxiliary field values at this point in space
8407 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8408 . a_x          - The auxiliary field derivatives at this point in space
8409 . t            - The current time
8410 . x            - The coordinates of this point
8411 . numConstants - The number of constants
8412 . constants    - The value of each constant
8413 - f            - The value of the function at this point in space
8414 
8415   Level: intermediate
8416 
8417   Note:
8418   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8419   The input `DM`, attached to localU, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8420   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8421   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8422 
8423   Developer Notes:
8424   This API is specific to only particular usage of `DM`
8425 
8426   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8427 
8428 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8429 @*/
8430 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8431 {
8432   PetscFunctionBegin;
8433   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8434   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8435   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8436   PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8437   PetscFunctionReturn(PETSC_SUCCESS);
8438 }
8439 
8440 /*@C
8441   DMProjectFieldLabel - This projects the given function of the input fields into the function space provided, putting the coefficients in a global vector, calculating only over the portion of the domain specified by the label.
8442 
8443   Not Collective
8444 
8445   Input Parameters:
8446 + dm     - The `DM`
8447 . time   - The time
8448 . label  - The `DMLabel` marking the portion of the domain to output
8449 . numIds - The number of label ids to use
8450 . ids    - The label ids to use for marking
8451 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8452 . comps  - The components to set in the output, or `NULL` for all components
8453 . U      - The input field vector
8454 . funcs  - The functions to evaluate, one per field
8455 - mode   - The insertion mode for values
8456 
8457   Output Parameter:
8458 . X - The output vector
8459 
8460   Calling sequence of `funcs`:
8461 + dim          - The spatial dimension
8462 . Nf           - The number of input fields
8463 . NfAux        - The number of input auxiliary fields
8464 . uOff         - The offset of each field in u[]
8465 . uOff_x       - The offset of each field in u_x[]
8466 . u            - The field values at this point in space
8467 . u_t          - The field time derivative at this point in space (or NULL)
8468 . u_x          - The field derivatives at this point in space
8469 . aOff         - The offset of each auxiliary field in u[]
8470 . aOff_x       - The offset of each auxiliary field in u_x[]
8471 . a            - The auxiliary field values at this point in space
8472 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8473 . a_x          - The auxiliary field derivatives at this point in space
8474 . t            - The current time
8475 . x            - The coordinates of this point
8476 . numConstants - The number of constants
8477 . constants    - The value of each constant
8478 - f            - The value of the function at this point in space
8479 
8480   Level: intermediate
8481 
8482   Note:
8483   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8484   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8485   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8486   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8487 
8488   Developer Notes:
8489   This API is specific to only particular usage of `DM`
8490 
8491   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8492 
8493 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8494 @*/
8495 PetscErrorCode DMProjectFieldLabel(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec U, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec X)
8496 {
8497   DM  dmIn;
8498   Vec localU, localX;
8499 
8500   PetscFunctionBegin;
8501   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8502   PetscCall(VecGetDM(U, &dmIn));
8503   PetscCall(DMGetLocalVector(dmIn, &localU));
8504   PetscCall(DMGetLocalVector(dm, &localX));
8505   PetscCall(VecSet(localX, 0.));
8506   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8507   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8508   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8509   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8510   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8511   PetscCall(DMRestoreLocalVector(dm, &localX));
8512   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8513   PetscFunctionReturn(PETSC_SUCCESS);
8514 }
8515 
8516 /*@C
8517   DMProjectBdFieldLabelLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector, calculating only over the portion of the domain boundary specified by the label.
8518 
8519   Not Collective
8520 
8521   Input Parameters:
8522 + dm     - The `DM`
8523 . time   - The time
8524 . label  - The `DMLabel` marking the portion of the domain boundary to output
8525 . numIds - The number of label ids to use
8526 . ids    - The label ids to use for marking
8527 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8528 . comps  - The components to set in the output, or `NULL` for all components
8529 . localU - The input field vector
8530 . funcs  - The functions to evaluate, one per field
8531 - mode   - The insertion mode for values
8532 
8533   Output Parameter:
8534 . localX - The output vector
8535 
8536   Calling sequence of `funcs`:
8537 + dim          - The spatial dimension
8538 . Nf           - The number of input fields
8539 . NfAux        - The number of input auxiliary fields
8540 . uOff         - The offset of each field in u[]
8541 . uOff_x       - The offset of each field in u_x[]
8542 . u            - The field values at this point in space
8543 . u_t          - The field time derivative at this point in space (or NULL)
8544 . u_x          - The field derivatives at this point in space
8545 . aOff         - The offset of each auxiliary field in u[]
8546 . aOff_x       - The offset of each auxiliary field in u_x[]
8547 . a            - The auxiliary field values at this point in space
8548 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8549 . a_x          - The auxiliary field derivatives at this point in space
8550 . t            - The current time
8551 . x            - The coordinates of this point
8552 . n            - The face normal
8553 . numConstants - The number of constants
8554 . constants    - The value of each constant
8555 - f            - The value of the function at this point in space
8556 
8557   Level: intermediate
8558 
8559   Note:
8560   There are three different `DM`s that potentially interact in this function. The output `DM`, dm, specifies the layout of the values calculates by funcs.
8561   The input `DM`, attached to U, may be different. For example, you can input the solution over the full domain, but output over a piece of the boundary, or
8562   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8563   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8564 
8565   Developer Notes:
8566   This API is specific to only particular usage of `DM`
8567 
8568   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8569 
8570 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8571 @*/
8572 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU, void (**funcs)(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], const PetscReal n[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]), InsertMode mode, Vec localX)
8573 {
8574   PetscFunctionBegin;
8575   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8576   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8577   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8578   PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8579   PetscFunctionReturn(PETSC_SUCCESS);
8580 }
8581 
8582 /*@C
8583   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8584 
8585   Collective
8586 
8587   Input Parameters:
8588 + dm    - The `DM`
8589 . time  - The time
8590 . funcs - The functions to evaluate for each field component
8591 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8592 - X     - The coefficient vector u_h, a global vector
8593 
8594   Output Parameter:
8595 . diff - The diff ||u - u_h||_2
8596 
8597   Level: developer
8598 
8599   Developer Notes:
8600   This API is specific to only particular usage of `DM`
8601 
8602   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8603 
8604 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8605 @*/
8606 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8607 {
8608   PetscFunctionBegin;
8609   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8610   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8611   PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff);
8612   PetscFunctionReturn(PETSC_SUCCESS);
8613 }
8614 
8615 /*@C
8616   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8617 
8618   Collective
8619 
8620   Input Parameters:
8621 + dm    - The `DM`
8622 . time  - The time
8623 . funcs - The gradient functions to evaluate for each field component
8624 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8625 . X     - The coefficient vector u_h, a global vector
8626 - n     - The vector to project along
8627 
8628   Output Parameter:
8629 . diff - The diff ||(grad u - grad u_h) . n||_2
8630 
8631   Level: developer
8632 
8633   Developer Notes:
8634   This API is specific to only particular usage of `DM`
8635 
8636   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8637 
8638 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8639 @*/
8640 PetscErrorCode DMComputeL2GradientDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff)
8641 {
8642   PetscFunctionBegin;
8643   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8644   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8645   PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff);
8646   PetscFunctionReturn(PETSC_SUCCESS);
8647 }
8648 
8649 /*@C
8650   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8651 
8652   Collective
8653 
8654   Input Parameters:
8655 + dm    - The `DM`
8656 . time  - The time
8657 . funcs - The functions to evaluate for each field component
8658 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8659 - X     - The coefficient vector u_h, a global vector
8660 
8661   Output Parameter:
8662 . diff - The array of differences, ||u^f - u^f_h||_2
8663 
8664   Level: developer
8665 
8666   Developer Notes:
8667   This API is specific to only particular usage of `DM`
8668 
8669   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8670 
8671 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8672 @*/
8673 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8674 {
8675   PetscFunctionBegin;
8676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8677   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8678   PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff);
8679   PetscFunctionReturn(PETSC_SUCCESS);
8680 }
8681 
8682 /*@C
8683   DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8684 
8685   Not Collective
8686 
8687   Input Parameter:
8688 . dm - The `DM`
8689 
8690   Output Parameters:
8691 + nranks - the number of neighbours
8692 - ranks  - the neighbors ranks
8693 
8694   Level: beginner
8695 
8696   Note:
8697   Do not free the array, it is freed when the `DM` is destroyed.
8698 
8699 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8700 @*/
8701 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8702 {
8703   PetscFunctionBegin;
8704   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8705   PetscUseTypeMethod(dm, getneighbors, nranks, ranks);
8706   PetscFunctionReturn(PETSC_SUCCESS);
8707 }
8708 
8709 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8710 
8711 /*
8712     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8713     This must be a different function because it requires DM which is not defined in the Mat library
8714 */
8715 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8716 {
8717   PetscFunctionBegin;
8718   if (coloring->ctype == IS_COLORING_LOCAL) {
8719     Vec x1local;
8720     DM  dm;
8721     PetscCall(MatGetDM(J, &dm));
8722     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8723     PetscCall(DMGetLocalVector(dm, &x1local));
8724     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8725     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8726     x1 = x1local;
8727   }
8728   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8729   if (coloring->ctype == IS_COLORING_LOCAL) {
8730     DM dm;
8731     PetscCall(MatGetDM(J, &dm));
8732     PetscCall(DMRestoreLocalVector(dm, &x1));
8733   }
8734   PetscFunctionReturn(PETSC_SUCCESS);
8735 }
8736 
8737 /*@
8738   MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8739 
8740   Input Parameters:
8741 + coloring   - The matrix to get the `DM` from
8742 - fdcoloring - the `MatFDColoring` object
8743 
8744   Level: advanced
8745 
8746   Developer Note:
8747   This routine exists because the PETSc `Mat` library does not know about the `DM` objects
8748 
8749 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8750 @*/
8751 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8752 {
8753   PetscFunctionBegin;
8754   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8755   PetscFunctionReturn(PETSC_SUCCESS);
8756 }
8757 
8758 /*@
8759   DMGetCompatibility - determine if two `DM`s are compatible
8760 
8761   Collective
8762 
8763   Input Parameters:
8764 + dm1 - the first `DM`
8765 - dm2 - the second `DM`
8766 
8767   Output Parameters:
8768 + compatible - whether or not the two `DM`s are compatible
8769 - set        - whether or not the compatible value was actually determined and set
8770 
8771   Level: advanced
8772 
8773   Notes:
8774   Two `DM`s are deemed compatible if they represent the same parallel decomposition
8775   of the same topology. This implies that the section (field data) on one
8776   "makes sense" with respect to the topology and parallel decomposition of the other.
8777   Loosely speaking, compatible `DM`s represent the same domain and parallel
8778   decomposition, but hold different data.
8779 
8780   Typically, one would confirm compatibility if intending to simultaneously iterate
8781   over a pair of vectors obtained from different `DM`s.
8782 
8783   For example, two `DMDA` objects are compatible if they have the same local
8784   and global sizes and the same stencil width. They can have different numbers
8785   of degrees of freedom per node. Thus, one could use the node numbering from
8786   either `DM` in bounds for a loop over vectors derived from either `DM`.
8787 
8788   Consider the operation of summing data living on a 2-dof `DMDA` to data living
8789   on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8790 .vb
8791   ...
8792   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8793   if (set && compatible)  {
8794     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8795     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8796     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8797     for (j=y; j<y+n; ++j) {
8798       for (i=x; i<x+m, ++i) {
8799         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8800       }
8801     }
8802     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8803     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8804   } else {
8805     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8806   }
8807   ...
8808 .ve
8809 
8810   Checking compatibility might be expensive for a given implementation of `DM`,
8811   or might be impossible to unambiguously confirm or deny. For this reason,
8812   this function may decline to determine compatibility, and hence users should
8813   always check the "set" output parameter.
8814 
8815   A `DM` is always compatible with itself.
8816 
8817   In the current implementation, `DM`s which live on "unequal" communicators
8818   (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8819   incompatible.
8820 
8821   This function is labeled "Collective," as information about all subdomains
8822   is required on each rank. However, in `DM` implementations which store all this
8823   information locally, this function may be merely "Logically Collective".
8824 
8825   Developer Note:
8826   Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8827   iff B is compatible with A. Thus, this function checks the implementations
8828   of both dm and dmc (if they are of different types), attempting to determine
8829   compatibility. It is left to `DM` implementers to ensure that symmetry is
8830   preserved. The simplest way to do this is, when implementing type-specific
8831   logic for this function, is to check for existing logic in the implementation
8832   of other `DM` types and let *set = PETSC_FALSE if found.
8833 
8834 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8835 @*/
8836 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8837 {
8838   PetscMPIInt compareResult;
8839   DMType      type, type2;
8840   PetscBool   sameType;
8841 
8842   PetscFunctionBegin;
8843   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8844   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8845 
8846   /* Declare a DM compatible with itself */
8847   if (dm1 == dm2) {
8848     *set        = PETSC_TRUE;
8849     *compatible = PETSC_TRUE;
8850     PetscFunctionReturn(PETSC_SUCCESS);
8851   }
8852 
8853   /* Declare a DM incompatible with a DM that lives on an "unequal"
8854      communicator. Note that this does not preclude compatibility with
8855      DMs living on "congruent" or "similar" communicators, but this must be
8856      determined by the implementation-specific logic */
8857   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8858   if (compareResult == MPI_UNEQUAL) {
8859     *set        = PETSC_TRUE;
8860     *compatible = PETSC_FALSE;
8861     PetscFunctionReturn(PETSC_SUCCESS);
8862   }
8863 
8864   /* Pass to the implementation-specific routine, if one exists. */
8865   if (dm1->ops->getcompatibility) {
8866     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8867     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8868   }
8869 
8870   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8871      with an implementation of this function from dm2 */
8872   PetscCall(DMGetType(dm1, &type));
8873   PetscCall(DMGetType(dm2, &type2));
8874   PetscCall(PetscStrcmp(type, type2, &sameType));
8875   if (!sameType && dm2->ops->getcompatibility) {
8876     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8877   } else {
8878     *set = PETSC_FALSE;
8879   }
8880   PetscFunctionReturn(PETSC_SUCCESS);
8881 }
8882 
8883 /*@C
8884   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8885 
8886   Logically Collective
8887 
8888   Input Parameters:
8889 + dm             - the `DM`
8890 . f              - the monitor function
8891 . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8892 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence
8893 
8894   Options Database Key:
8895 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8896                        does not cancel those set via the options database.
8897 
8898   Level: intermediate
8899 
8900   Note:
8901   Several different monitoring routines may be set by calling
8902   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8903   order in which they were set.
8904 
8905   Fortran Note:
8906   Only a single monitor function can be set for each `DM` object
8907 
8908   Developer Note:
8909   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8910 
8911 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`, `PetscCtxDestroyFn`
8912 @*/
8913 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy)
8914 {
8915   PetscInt m;
8916 
8917   PetscFunctionBegin;
8918   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8919   for (m = 0; m < dm->numbermonitors; ++m) {
8920     PetscBool identical;
8921 
8922     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))f, mctx, monitordestroy, (PetscErrorCode (*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8923     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
8924   }
8925   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8926   dm->monitor[dm->numbermonitors]          = f;
8927   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8928   dm->monitorcontext[dm->numbermonitors++] = mctx;
8929   PetscFunctionReturn(PETSC_SUCCESS);
8930 }
8931 
8932 /*@
8933   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8934 
8935   Logically Collective
8936 
8937   Input Parameter:
8938 . dm - the DM
8939 
8940   Options Database Key:
8941 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8942   into a code by calls to `DMonitorSet()`, but does not cancel those
8943   set via the options database
8944 
8945   Level: intermediate
8946 
8947   Note:
8948   There is no way to clear one specific monitor from a `DM` object.
8949 
8950 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8951 @*/
8952 PetscErrorCode DMMonitorCancel(DM dm)
8953 {
8954   PetscInt m;
8955 
8956   PetscFunctionBegin;
8957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8958   for (m = 0; m < dm->numbermonitors; ++m) {
8959     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8960   }
8961   dm->numbermonitors = 0;
8962   PetscFunctionReturn(PETSC_SUCCESS);
8963 }
8964 
8965 /*@C
8966   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8967 
8968   Collective
8969 
8970   Input Parameters:
8971 + dm           - `DM` object you wish to monitor
8972 . name         - the monitor type one is seeking
8973 . help         - message indicating what monitoring is done
8974 . manual       - manual page for the monitor
8975 . monitor      - the monitor function, this must use a `PetscViewerFormat` as its context
8976 - monitorsetup - a function that is called once ONLY if the user selected this monitor that may set additional features of the `DM` or `PetscViewer` objects
8977 
8978   Output Parameter:
8979 . flg - Flag set if the monitor was created
8980 
8981   Level: developer
8982 
8983 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8984           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8985           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
8986           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8987           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8988           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8989           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8990 @*/
8991 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8992 {
8993   PetscViewer       viewer;
8994   PetscViewerFormat format;
8995 
8996   PetscFunctionBegin;
8997   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8998   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
8999   if (*flg) {
9000     PetscViewerAndFormat *vf;
9001 
9002     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
9003     PetscCall(PetscViewerDestroy(&viewer));
9004     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
9005     PetscCall(DMMonitorSet(dm, monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
9006   }
9007   PetscFunctionReturn(PETSC_SUCCESS);
9008 }
9009 
9010 /*@
9011   DMMonitor - runs the user provided monitor routines, if they exist
9012 
9013   Collective
9014 
9015   Input Parameter:
9016 . dm - The `DM`
9017 
9018   Level: developer
9019 
9020   Developer Note:
9021   Note should indicate when during the life of the `DM` the monitor is run. It appears to be
9022   related to the discretization process seems rather specialized since some `DM` have no
9023   concept of discretization.
9024 
9025 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
9026 @*/
9027 PetscErrorCode DMMonitor(DM dm)
9028 {
9029   PetscInt m;
9030 
9031   PetscFunctionBegin;
9032   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
9033   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9034   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9035   PetscFunctionReturn(PETSC_SUCCESS);
9036 }
9037 
9038 /*@
9039   DMComputeError - Computes the error assuming the user has provided the exact solution functions
9040 
9041   Collective
9042 
9043   Input Parameters:
9044 + dm  - The `DM`
9045 - sol - The solution vector
9046 
9047   Input/Output Parameter:
9048 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
9049            contains the error in each field
9050 
9051   Output Parameter:
9052 . errorVec - A vector to hold the cellwise error (may be `NULL`)
9053 
9054   Level: developer
9055 
9056   Note:
9057   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
9058 
9059 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9060 @*/
9061 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9062 {
9063   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9064   void    **ctxs;
9065   PetscReal time;
9066   PetscInt  Nf, f, Nds, s;
9067 
9068   PetscFunctionBegin;
9069   PetscCall(DMGetNumFields(dm, &Nf));
9070   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9071   PetscCall(DMGetNumDS(dm, &Nds));
9072   for (s = 0; s < Nds; ++s) {
9073     PetscDS         ds;
9074     DMLabel         label;
9075     IS              fieldIS;
9076     const PetscInt *fields;
9077     PetscInt        dsNf;
9078 
9079     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
9080     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9081     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9082     for (f = 0; f < dsNf; ++f) {
9083       const PetscInt field = fields[f];
9084       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9085     }
9086     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9087   }
9088   for (f = 0; f < Nf; ++f) PetscCheck(exactSol[f], PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to calculate error, missing for field %" PetscInt_FMT, f);
9089   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9090   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9091   if (errorVec) {
9092     DM             edm;
9093     DMPolytopeType ct;
9094     PetscBool      simplex;
9095     PetscInt       dim, cStart, Nf;
9096 
9097     PetscCall(DMClone(dm, &edm));
9098     PetscCall(DMGetDimension(edm, &dim));
9099     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9100     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9101     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9102     PetscCall(DMGetNumFields(dm, &Nf));
9103     for (f = 0; f < Nf; ++f) {
9104       PetscFE         fe, efe;
9105       PetscQuadrature q;
9106       const char     *name;
9107 
9108       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
9109       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9110       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
9111       PetscCall(PetscObjectSetName((PetscObject)efe, name));
9112       PetscCall(PetscFEGetQuadrature(fe, &q));
9113       PetscCall(PetscFESetQuadrature(efe, q));
9114       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
9115       PetscCall(PetscFEDestroy(&efe));
9116     }
9117     PetscCall(DMCreateDS(edm));
9118 
9119     PetscCall(DMCreateGlobalVector(edm, errorVec));
9120     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
9121     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9122     PetscCall(DMDestroy(&edm));
9123   }
9124   PetscCall(PetscFree2(exactSol, ctxs));
9125   PetscFunctionReturn(PETSC_SUCCESS);
9126 }
9127 
9128 /*@
9129   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
9130 
9131   Not Collective
9132 
9133   Input Parameter:
9134 . dm - The `DM`
9135 
9136   Output Parameter:
9137 . numAux - The number of auxiliary data vectors
9138 
9139   Level: advanced
9140 
9141 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
9142 @*/
9143 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9144 {
9145   PetscFunctionBegin;
9146   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9147   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9148   PetscFunctionReturn(PETSC_SUCCESS);
9149 }
9150 
9151 /*@
9152   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9153 
9154   Not Collective
9155 
9156   Input Parameters:
9157 + dm    - The `DM`
9158 . label - The `DMLabel`
9159 . value - The label value indicating the region
9160 - part  - The equation part, or 0 if unused
9161 
9162   Output Parameter:
9163 . aux - The `Vec` holding auxiliary field data
9164 
9165   Level: advanced
9166 
9167   Note:
9168   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9169 
9170 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
9171 @*/
9172 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9173 {
9174   PetscHashAuxKey key, wild = {NULL, 0, 0};
9175   PetscBool       has;
9176 
9177   PetscFunctionBegin;
9178   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9179   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9180   key.label = label;
9181   key.value = value;
9182   key.part  = part;
9183   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9184   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
9185   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9186   PetscFunctionReturn(PETSC_SUCCESS);
9187 }
9188 
9189 /*@
9190   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
9191 
9192   Not Collective because auxiliary vectors are not parallel
9193 
9194   Input Parameters:
9195 + dm    - The `DM`
9196 . label - The `DMLabel`
9197 . value - The label value indicating the region
9198 . part  - The equation part, or 0 if unused
9199 - aux   - The `Vec` holding auxiliary field data
9200 
9201   Level: advanced
9202 
9203 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
9204 @*/
9205 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9206 {
9207   Vec             old;
9208   PetscHashAuxKey key;
9209 
9210   PetscFunctionBegin;
9211   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9212   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9213   key.label = label;
9214   key.value = value;
9215   key.part  = part;
9216   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9217   PetscCall(PetscObjectReference((PetscObject)aux));
9218   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9219   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9220   PetscCall(VecDestroy(&old));
9221   PetscFunctionReturn(PETSC_SUCCESS);
9222 }
9223 
9224 /*@
9225   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9226 
9227   Not Collective
9228 
9229   Input Parameter:
9230 . dm - The `DM`
9231 
9232   Output Parameters:
9233 + labels - The `DMLabel`s for each `Vec`
9234 . values - The label values for each `Vec`
9235 - parts  - The equation parts for each `Vec`
9236 
9237   Level: advanced
9238 
9239   Note:
9240   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9241 
9242 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9243 @*/
9244 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9245 {
9246   PetscHashAuxKey *keys;
9247   PetscInt         n, i, off = 0;
9248 
9249   PetscFunctionBegin;
9250   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9251   PetscAssertPointer(labels, 2);
9252   PetscAssertPointer(values, 3);
9253   PetscAssertPointer(parts, 4);
9254   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9255   PetscCall(PetscMalloc1(n, &keys));
9256   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9257   for (i = 0; i < n; ++i) {
9258     labels[i] = keys[i].label;
9259     values[i] = keys[i].value;
9260     parts[i]  = keys[i].part;
9261   }
9262   PetscCall(PetscFree(keys));
9263   PetscFunctionReturn(PETSC_SUCCESS);
9264 }
9265 
9266 /*@
9267   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9268 
9269   Not Collective
9270 
9271   Input Parameter:
9272 . dm - The `DM`
9273 
9274   Output Parameter:
9275 . dmNew - The new `DM`, now with the same auxiliary data
9276 
9277   Level: advanced
9278 
9279   Note:
9280   This is a shallow copy of the auxiliary vectors
9281 
9282 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9283 @*/
9284 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9285 {
9286   PetscFunctionBegin;
9287   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9288   PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2);
9289   if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS);
9290   PetscCall(DMClearAuxiliaryVec(dmNew));
9291 
9292   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9293   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9294   {
9295     Vec     *auxData;
9296     PetscInt n, i, off = 0;
9297 
9298     PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n));
9299     PetscCall(PetscMalloc1(n, &auxData));
9300     PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData));
9301     for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i]));
9302     PetscCall(PetscFree(auxData));
9303   }
9304   PetscFunctionReturn(PETSC_SUCCESS);
9305 }
9306 
9307 /*@
9308   DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one
9309 
9310   Not Collective
9311 
9312   Input Parameter:
9313 . dm - The `DM`
9314 
9315   Level: advanced
9316 
9317 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9318 @*/
9319 PetscErrorCode DMClearAuxiliaryVec(DM dm)
9320 {
9321   Vec     *auxData;
9322   PetscInt n, i, off = 0;
9323 
9324   PetscFunctionBegin;
9325   PetscCall(PetscHMapAuxGetSize(dm->auxData, &n));
9326   PetscCall(PetscMalloc1(n, &auxData));
9327   PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData));
9328   for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i]));
9329   PetscCall(PetscFree(auxData));
9330   PetscCall(PetscHMapAuxDestroy(&dm->auxData));
9331   PetscCall(PetscHMapAuxCreate(&dm->auxData));
9332   PetscFunctionReturn(PETSC_SUCCESS);
9333 }
9334 
9335 /*@
9336   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9337 
9338   Not Collective
9339 
9340   Input Parameters:
9341 + ct         - The `DMPolytopeType`
9342 . sourceCone - The source arrangement of faces
9343 - targetCone - The target arrangement of faces
9344 
9345   Output Parameters:
9346 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9347 - found - Flag indicating that a suitable orientation was found
9348 
9349   Level: advanced
9350 
9351   Note:
9352   An arrangement is a face order combined with an orientation for each face
9353 
9354   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9355   that labels each arrangement (face ordering plus orientation for each face).
9356 
9357   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9358 
9359 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9360 @*/
9361 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9362 {
9363   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9364   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9365   PetscInt       o, c;
9366 
9367   PetscFunctionBegin;
9368   if (!nO) {
9369     *ornt  = 0;
9370     *found = PETSC_TRUE;
9371     PetscFunctionReturn(PETSC_SUCCESS);
9372   }
9373   for (o = -nO; o < nO; ++o) {
9374     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
9375 
9376     for (c = 0; c < cS; ++c)
9377       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9378     if (c == cS) {
9379       *ornt = o;
9380       break;
9381     }
9382   }
9383   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9384   PetscFunctionReturn(PETSC_SUCCESS);
9385 }
9386 
9387 /*@
9388   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9389 
9390   Not Collective
9391 
9392   Input Parameters:
9393 + ct         - The `DMPolytopeType`
9394 . sourceCone - The source arrangement of faces
9395 - targetCone - The target arrangement of faces
9396 
9397   Output Parameter:
9398 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9399 
9400   Level: advanced
9401 
9402   Note:
9403   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9404 
9405   Developer Note:
9406   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9407 
9408 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9409 @*/
9410 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9411 {
9412   PetscBool found;
9413 
9414   PetscFunctionBegin;
9415   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9416   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9417   PetscFunctionReturn(PETSC_SUCCESS);
9418 }
9419 
9420 /*@
9421   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9422 
9423   Not Collective
9424 
9425   Input Parameters:
9426 + ct         - The `DMPolytopeType`
9427 . sourceVert - The source arrangement of vertices
9428 - targetVert - The target arrangement of vertices
9429 
9430   Output Parameters:
9431 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9432 - found - Flag indicating that a suitable orientation was found
9433 
9434   Level: advanced
9435 
9436   Notes:
9437   An arrangement is a vertex order
9438 
9439   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9440   that labels each arrangement (vertex ordering).
9441 
9442   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9443 
9444 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()`
9445 @*/
9446 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9447 {
9448   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9449   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9450   PetscInt       o, c;
9451 
9452   PetscFunctionBegin;
9453   if (!nO) {
9454     *ornt  = 0;
9455     *found = PETSC_TRUE;
9456     PetscFunctionReturn(PETSC_SUCCESS);
9457   }
9458   for (o = -nO; o < nO; ++o) {
9459     const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o);
9460 
9461     for (c = 0; c < cS; ++c)
9462       if (sourceVert[arr[c]] != targetVert[c]) break;
9463     if (c == cS) {
9464       *ornt = o;
9465       break;
9466     }
9467   }
9468   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9469   PetscFunctionReturn(PETSC_SUCCESS);
9470 }
9471 
9472 /*@
9473   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9474 
9475   Not Collective
9476 
9477   Input Parameters:
9478 + ct         - The `DMPolytopeType`
9479 . sourceCone - The source arrangement of vertices
9480 - targetCone - The target arrangement of vertices
9481 
9482   Output Parameter:
9483 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9484 
9485   Level: advanced
9486 
9487   Note:
9488   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9489 
9490   Developer Note:
9491   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9492 
9493 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9494 @*/
9495 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9496 {
9497   PetscBool found;
9498 
9499   PetscFunctionBegin;
9500   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9501   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9502   PetscFunctionReturn(PETSC_SUCCESS);
9503 }
9504 
9505 /*@
9506   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9507 
9508   Not Collective
9509 
9510   Input Parameters:
9511 + ct    - The `DMPolytopeType`
9512 - point - Coordinates of the point
9513 
9514   Output Parameter:
9515 . inside - Flag indicating whether the point is inside the reference cell of given type
9516 
9517   Level: advanced
9518 
9519 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9520 @*/
9521 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9522 {
9523   PetscReal sum = 0.0;
9524   PetscInt  d;
9525 
9526   PetscFunctionBegin;
9527   *inside = PETSC_TRUE;
9528   switch (ct) {
9529   case DM_POLYTOPE_TRIANGLE:
9530   case DM_POLYTOPE_TETRAHEDRON:
9531     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9532       if (point[d] < -1.0) {
9533         *inside = PETSC_FALSE;
9534         break;
9535       }
9536       sum += point[d];
9537     }
9538     if (sum > PETSC_SMALL) {
9539       *inside = PETSC_FALSE;
9540       break;
9541     }
9542     break;
9543   case DM_POLYTOPE_QUADRILATERAL:
9544   case DM_POLYTOPE_HEXAHEDRON:
9545     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9546       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9547         *inside = PETSC_FALSE;
9548         break;
9549       }
9550     break;
9551   default:
9552     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9553   }
9554   PetscFunctionReturn(PETSC_SUCCESS);
9555 }
9556 
9557 /*@
9558   DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default
9559 
9560   Logically collective
9561 
9562   Input Parameters:
9563 + dm      - The DM
9564 - reorder - Flag for reordering
9565 
9566   Level: intermediate
9567 
9568 .seealso: `DMReorderSectionGetDefault()`
9569 @*/
9570 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder)
9571 {
9572   PetscFunctionBegin;
9573   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9574   PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder));
9575   PetscFunctionReturn(PETSC_SUCCESS);
9576 }
9577 
9578 /*@
9579   DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default
9580 
9581   Not collective
9582 
9583   Input Parameter:
9584 . dm - The DM
9585 
9586   Output Parameter:
9587 . reorder - Flag for reordering
9588 
9589   Level: intermediate
9590 
9591 .seealso: `DMReorderSetDefault()`
9592 @*/
9593 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder)
9594 {
9595   PetscFunctionBegin;
9596   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9597   PetscAssertPointer(reorder, 2);
9598   *reorder = DM_REORDER_DEFAULT_NOTSET;
9599   PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder));
9600   PetscFunctionReturn(PETSC_SUCCESS);
9601 }
9602 
9603 /*@
9604   DMReorderSectionSetType - Set the type of local section reordering
9605 
9606   Logically collective
9607 
9608   Input Parameters:
9609 + dm      - The DM
9610 - reorder - The reordering method
9611 
9612   Level: intermediate
9613 
9614 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()`
9615 @*/
9616 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder)
9617 {
9618   PetscFunctionBegin;
9619   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9620   PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder));
9621   PetscFunctionReturn(PETSC_SUCCESS);
9622 }
9623 
9624 /*@
9625   DMReorderSectionGetType - Get the reordering type for the local section
9626 
9627   Not collective
9628 
9629   Input Parameter:
9630 . dm - The DM
9631 
9632   Output Parameter:
9633 . reorder - The reordering method
9634 
9635   Level: intermediate
9636 
9637 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()`
9638 @*/
9639 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder)
9640 {
9641   PetscFunctionBegin;
9642   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9643   PetscAssertPointer(reorder, 2);
9644   *reorder = NULL;
9645   PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder));
9646   PetscFunctionReturn(PETSC_SUCCESS);
9647 }
9648