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