xref: /petsc/src/dm/interface/dm.c (revision d7d2d1d2babbf975e9544da80073779625dd96d9)
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   DMGetSection - Get the `PetscSection` encoding the local data layout for the `DM`.   This is equivalent to `DMGetLocalSection()`. Deprecated in v3.12
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 `PetscSection` created by the `DM`
4271 
4272   Level: advanced
4273 
4274   Notes:
4275   Use `DMGetLocalSection()` in new code.
4276 
4277   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4278 
4279 .seealso: [](ch_dmbase), `DM`, `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4280 @*/
4281 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4282 {
4283   PetscFunctionBegin;
4284   PetscCall(DMGetLocalSection(dm, section));
4285   PetscFunctionReturn(PETSC_SUCCESS);
4286 }
4287 
4288 /*@
4289   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4290 
4291   Input Parameter:
4292 . dm - The `DM`
4293 
4294   Output Parameter:
4295 . section - The `PetscSection`
4296 
4297   Options Database Key:
4298 . -dm_petscsection_view - View the section created by the `DM`
4299 
4300   Level: intermediate
4301 
4302   Note:
4303   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4304 
4305 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4306 @*/
4307 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4308 {
4309   PetscFunctionBegin;
4310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4311   PetscAssertPointer(section, 2);
4312   if (!dm->localSection && dm->ops->createlocalsection) {
4313     PetscInt d;
4314 
4315     if (dm->setfromoptionscalled) {
4316       PetscObject       obj = (PetscObject)dm;
4317       PetscViewer       viewer;
4318       PetscViewerFormat format;
4319       PetscBool         flg;
4320 
4321       PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4322       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4323       for (d = 0; d < dm->Nds; ++d) {
4324         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4325         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4326       }
4327       if (flg) {
4328         PetscCall(PetscViewerFlush(viewer));
4329         PetscCall(PetscViewerPopFormat(viewer));
4330         PetscCall(PetscViewerDestroy(&viewer));
4331       }
4332     }
4333     PetscUseTypeMethod(dm, createlocalsection);
4334     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4335   }
4336   *section = dm->localSection;
4337   PetscFunctionReturn(PETSC_SUCCESS);
4338 }
4339 
4340 /*@
4341   DMSetSection - Set the `PetscSection` encoding the local data layout for the `DM`.  This is equivalent to `DMSetLocalSection()`. Deprecated in v3.12
4342 
4343   Input Parameters:
4344 + dm      - The `DM`
4345 - section - The `PetscSection`
4346 
4347   Level: advanced
4348 
4349   Notes:
4350   Use `DMSetLocalSection()` in new code.
4351 
4352   Any existing `PetscSection` will be destroyed
4353 
4354 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4355 @*/
4356 PetscErrorCode DMSetSection(DM dm, PetscSection section)
4357 {
4358   PetscFunctionBegin;
4359   PetscCall(DMSetLocalSection(dm, section));
4360   PetscFunctionReturn(PETSC_SUCCESS);
4361 }
4362 
4363 /*@
4364   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4365 
4366   Input Parameters:
4367 + dm      - The `DM`
4368 - section - The `PetscSection`
4369 
4370   Level: intermediate
4371 
4372   Note:
4373   Any existing Section will be destroyed
4374 
4375 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4376 @*/
4377 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4378 {
4379   PetscInt numFields = 0;
4380   PetscInt f;
4381 
4382   PetscFunctionBegin;
4383   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4384   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4385   PetscCall(PetscObjectReference((PetscObject)section));
4386   PetscCall(PetscSectionDestroy(&dm->localSection));
4387   dm->localSection = section;
4388   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4389   if (numFields) {
4390     PetscCall(DMSetNumFields(dm, numFields));
4391     for (f = 0; f < numFields; ++f) {
4392       PetscObject disc;
4393       const char *name;
4394 
4395       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4396       PetscCall(DMGetField(dm, f, NULL, &disc));
4397       PetscCall(PetscObjectSetName(disc, name));
4398     }
4399   }
4400   /* The global section and the SectionSF will be rebuilt
4401      in the next call to DMGetGlobalSection() and DMGetSectionSF(). */
4402   PetscCall(PetscSectionDestroy(&dm->globalSection));
4403   PetscCall(PetscSFDestroy(&dm->sectionSF));
4404   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4405 
4406   /* Clear scratch vectors */
4407   PetscCall(DMClearGlobalVectors(dm));
4408   PetscCall(DMClearLocalVectors(dm));
4409   PetscCall(DMClearNamedGlobalVectors(dm));
4410   PetscCall(DMClearNamedLocalVectors(dm));
4411   PetscFunctionReturn(PETSC_SUCCESS);
4412 }
4413 
4414 /*@C
4415   DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure.
4416 
4417   Input Parameter:
4418 . dm - The `DM`
4419 
4420   Output Parameters:
4421 + perm        - A permutation of the mesh points in the chart
4422 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking
4423 
4424   Level: developer
4425 
4426 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4427 @*/
4428 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts)
4429 {
4430   PetscFunctionBegin;
4431   *perm        = NULL;
4432   *blockStarts = NULL;
4433   PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts);
4434   PetscFunctionReturn(PETSC_SUCCESS);
4435 }
4436 
4437 /*@
4438   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4439 
4440   not Collective
4441 
4442   Input Parameter:
4443 . dm - The `DM`
4444 
4445   Output Parameters:
4446 + 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.
4447 . 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.
4448 - bias    - Vector containing bias to be added to constrained dofs
4449 
4450   Level: advanced
4451 
4452   Note:
4453   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4454 
4455 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4456 @*/
4457 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4458 {
4459   PetscFunctionBegin;
4460   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4461   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4462   if (section) *section = dm->defaultConstraint.section;
4463   if (mat) *mat = dm->defaultConstraint.mat;
4464   if (bias) *bias = dm->defaultConstraint.bias;
4465   PetscFunctionReturn(PETSC_SUCCESS);
4466 }
4467 
4468 /*@
4469   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4470 
4471   Collective
4472 
4473   Input Parameters:
4474 + dm      - The `DM`
4475 . 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).
4476 . 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).
4477 - 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).
4478 
4479   Level: advanced
4480 
4481   Notes:
4482   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()`.
4483 
4484   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.
4485 
4486   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4487 
4488 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4489 @*/
4490 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4491 {
4492   PetscMPIInt result;
4493 
4494   PetscFunctionBegin;
4495   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4496   if (section) {
4497     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4498     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4499     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4500   }
4501   if (mat) {
4502     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4503     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4504     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4505   }
4506   if (bias) {
4507     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4508     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4509     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4510   }
4511   PetscCall(PetscObjectReference((PetscObject)section));
4512   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4513   dm->defaultConstraint.section = section;
4514   PetscCall(PetscObjectReference((PetscObject)mat));
4515   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4516   dm->defaultConstraint.mat = mat;
4517   PetscCall(PetscObjectReference((PetscObject)bias));
4518   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4519   dm->defaultConstraint.bias = bias;
4520   PetscFunctionReturn(PETSC_SUCCESS);
4521 }
4522 
4523 #if defined(PETSC_USE_DEBUG)
4524 /*
4525   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4526 
4527   Input Parameters:
4528 + dm - The `DM`
4529 . localSection - `PetscSection` describing the local data layout
4530 - globalSection - `PetscSection` describing the global data layout
4531 
4532   Level: intermediate
4533 
4534 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4535 */
4536 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4537 {
4538   MPI_Comm        comm;
4539   PetscLayout     layout;
4540   const PetscInt *ranges;
4541   PetscInt        pStart, pEnd, p, nroots;
4542   PetscMPIInt     size, rank;
4543   PetscBool       valid = PETSC_TRUE, gvalid;
4544 
4545   PetscFunctionBegin;
4546   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4547   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4548   PetscCallMPI(MPI_Comm_size(comm, &size));
4549   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4550   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4551   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4552   PetscCall(PetscLayoutCreate(comm, &layout));
4553   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4554   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4555   PetscCall(PetscLayoutSetUp(layout));
4556   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4557   for (p = pStart; p < pEnd; ++p) {
4558     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4559 
4560     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4561     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4562     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4563     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4564     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4565     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4566     if (!gdof) continue; /* Censored point */
4567     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4568       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4569       valid = PETSC_FALSE;
4570     }
4571     if (gcdof && (gcdof != cdof)) {
4572       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4573       valid = PETSC_FALSE;
4574     }
4575     if (gdof < 0) {
4576       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4577       for (d = 0; d < gsize; ++d) {
4578         PetscInt offset = -(goff + 1) + d, r;
4579 
4580         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4581         if (r < 0) r = -(r + 2);
4582         if ((r < 0) || (r >= size)) {
4583           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4584           valid = PETSC_FALSE;
4585           break;
4586         }
4587       }
4588     }
4589   }
4590   PetscCall(PetscLayoutDestroy(&layout));
4591   PetscCall(PetscSynchronizedFlush(comm, NULL));
4592   PetscCallMPI(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm));
4593   if (!gvalid) {
4594     PetscCall(DMView(dm, NULL));
4595     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4596   }
4597   PetscFunctionReturn(PETSC_SUCCESS);
4598 }
4599 #endif
4600 
4601 PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4602 {
4603   PetscErrorCode (*f)(DM, PetscSF *);
4604 
4605   PetscFunctionBegin;
4606   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4607   PetscAssertPointer(sf, 2);
4608   PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4609   if (f) PetscCall(f(dm, sf));
4610   else *sf = dm->sf;
4611   PetscFunctionReturn(PETSC_SUCCESS);
4612 }
4613 
4614 /*@
4615   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4616 
4617   Collective
4618 
4619   Input Parameter:
4620 . dm - The `DM`
4621 
4622   Output Parameter:
4623 . section - The `PetscSection`
4624 
4625   Level: intermediate
4626 
4627   Note:
4628   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4629 
4630 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4631 @*/
4632 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4633 {
4634   PetscFunctionBegin;
4635   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4636   PetscAssertPointer(section, 2);
4637   if (!dm->globalSection) {
4638     PetscSection s;
4639     PetscSF      sf;
4640 
4641     PetscCall(DMGetLocalSection(dm, &s));
4642     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4643     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4644     PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4645     PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4646     PetscCall(PetscLayoutDestroy(&dm->map));
4647     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4648     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4649   }
4650   *section = dm->globalSection;
4651   PetscFunctionReturn(PETSC_SUCCESS);
4652 }
4653 
4654 /*@
4655   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4656 
4657   Input Parameters:
4658 + dm      - The `DM`
4659 - section - The PetscSection, or `NULL`
4660 
4661   Level: intermediate
4662 
4663   Note:
4664   Any existing `PetscSection` will be destroyed
4665 
4666 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4667 @*/
4668 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4669 {
4670   PetscFunctionBegin;
4671   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4672   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4673   PetscCall(PetscObjectReference((PetscObject)section));
4674   PetscCall(PetscSectionDestroy(&dm->globalSection));
4675   dm->globalSection = section;
4676 #if defined(PETSC_USE_DEBUG)
4677   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4678 #endif
4679   /* Clear global scratch vectors and sectionSF */
4680   PetscCall(PetscSFDestroy(&dm->sectionSF));
4681   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4682   PetscCall(DMClearGlobalVectors(dm));
4683   PetscCall(DMClearNamedGlobalVectors(dm));
4684   PetscFunctionReturn(PETSC_SUCCESS);
4685 }
4686 
4687 /*@
4688   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4689   it is created from the default `PetscSection` layouts in the `DM`.
4690 
4691   Input Parameter:
4692 . dm - The `DM`
4693 
4694   Output Parameter:
4695 . sf - The `PetscSF`
4696 
4697   Level: intermediate
4698 
4699   Note:
4700   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4701 
4702 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4703 @*/
4704 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4705 {
4706   PetscInt nroots;
4707 
4708   PetscFunctionBegin;
4709   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4710   PetscAssertPointer(sf, 2);
4711   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4712   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4713   if (nroots < 0) {
4714     PetscSection section, gSection;
4715 
4716     PetscCall(DMGetLocalSection(dm, &section));
4717     if (section) {
4718       PetscCall(DMGetGlobalSection(dm, &gSection));
4719       PetscCall(DMCreateSectionSF(dm, section, gSection));
4720     } else {
4721       *sf = NULL;
4722       PetscFunctionReturn(PETSC_SUCCESS);
4723     }
4724   }
4725   *sf = dm->sectionSF;
4726   PetscFunctionReturn(PETSC_SUCCESS);
4727 }
4728 
4729 /*@
4730   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4731 
4732   Input Parameters:
4733 + dm - The `DM`
4734 - sf - The `PetscSF`
4735 
4736   Level: intermediate
4737 
4738   Note:
4739   Any previous `PetscSF` is destroyed
4740 
4741 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4742 @*/
4743 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4744 {
4745   PetscFunctionBegin;
4746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4747   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4748   PetscCall(PetscObjectReference((PetscObject)sf));
4749   PetscCall(PetscSFDestroy(&dm->sectionSF));
4750   dm->sectionSF = sf;
4751   PetscFunctionReturn(PETSC_SUCCESS);
4752 }
4753 
4754 /*@
4755   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4756   describing the data layout.
4757 
4758   Input Parameters:
4759 + dm            - The `DM`
4760 . localSection  - `PetscSection` describing the local data layout
4761 - globalSection - `PetscSection` describing the global data layout
4762 
4763   Level: developer
4764 
4765   Note:
4766   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4767 
4768   Developer Note:
4769   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4770   directly into the `DM`, perhaps this function should not take the local and global sections as
4771   input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing
4772   they create, this returns nothing
4773 
4774 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4775 @*/
4776 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4777 {
4778   PetscFunctionBegin;
4779   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4780   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4781   PetscFunctionReturn(PETSC_SUCCESS);
4782 }
4783 
4784 /*@
4785   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4786 
4787   Not collective but the resulting `PetscSF` is collective
4788 
4789   Input Parameter:
4790 . dm - The `DM`
4791 
4792   Output Parameter:
4793 . sf - The `PetscSF`
4794 
4795   Level: intermediate
4796 
4797   Note:
4798   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4799 
4800 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4801 @*/
4802 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4803 {
4804   PetscFunctionBegin;
4805   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4806   PetscAssertPointer(sf, 2);
4807   *sf = dm->sf;
4808   PetscFunctionReturn(PETSC_SUCCESS);
4809 }
4810 
4811 /*@
4812   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4813 
4814   Collective
4815 
4816   Input Parameters:
4817 + dm - The `DM`
4818 - sf - The `PetscSF`
4819 
4820   Level: intermediate
4821 
4822 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4823 @*/
4824 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4825 {
4826   PetscFunctionBegin;
4827   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4828   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4829   PetscCall(PetscObjectReference((PetscObject)sf));
4830   PetscCall(PetscSFDestroy(&dm->sf));
4831   dm->sf = sf;
4832   PetscFunctionReturn(PETSC_SUCCESS);
4833 }
4834 
4835 /*@
4836   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4837 
4838   Input Parameter:
4839 . dm - The `DM`
4840 
4841   Output Parameter:
4842 . sf - The `PetscSF`
4843 
4844   Level: intermediate
4845 
4846   Note:
4847   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4848 
4849 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4850 @*/
4851 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4852 {
4853   PetscFunctionBegin;
4854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4855   PetscAssertPointer(sf, 2);
4856   *sf = dm->sfNatural;
4857   PetscFunctionReturn(PETSC_SUCCESS);
4858 }
4859 
4860 /*@
4861   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4862 
4863   Input Parameters:
4864 + dm - The DM
4865 - sf - The PetscSF
4866 
4867   Level: intermediate
4868 
4869 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4870 @*/
4871 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4872 {
4873   PetscFunctionBegin;
4874   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4875   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4876   PetscCall(PetscObjectReference((PetscObject)sf));
4877   PetscCall(PetscSFDestroy(&dm->sfNatural));
4878   dm->sfNatural = sf;
4879   PetscFunctionReturn(PETSC_SUCCESS);
4880 }
4881 
4882 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4883 {
4884   PetscClassId id;
4885 
4886   PetscFunctionBegin;
4887   PetscCall(PetscObjectGetClassId(disc, &id));
4888   if (id == PETSCFE_CLASSID) {
4889     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4890   } else if (id == PETSCFV_CLASSID) {
4891     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4892   } else {
4893     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4894   }
4895   PetscFunctionReturn(PETSC_SUCCESS);
4896 }
4897 
4898 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4899 {
4900   RegionField *tmpr;
4901   PetscInt     Nf = dm->Nf, f;
4902 
4903   PetscFunctionBegin;
4904   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4905   PetscCall(PetscMalloc1(NfNew, &tmpr));
4906   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4907   for (f = Nf; f < NfNew; ++f) {
4908     tmpr[f].disc        = NULL;
4909     tmpr[f].label       = NULL;
4910     tmpr[f].avoidTensor = PETSC_FALSE;
4911   }
4912   PetscCall(PetscFree(dm->fields));
4913   dm->Nf     = NfNew;
4914   dm->fields = tmpr;
4915   PetscFunctionReturn(PETSC_SUCCESS);
4916 }
4917 
4918 /*@
4919   DMClearFields - Remove all fields from the `DM`
4920 
4921   Logically Collective
4922 
4923   Input Parameter:
4924 . dm - The `DM`
4925 
4926   Level: intermediate
4927 
4928 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4929 @*/
4930 PetscErrorCode DMClearFields(DM dm)
4931 {
4932   PetscInt f;
4933 
4934   PetscFunctionBegin;
4935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4936   for (f = 0; f < dm->Nf; ++f) {
4937     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4938     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4939   }
4940   PetscCall(PetscFree(dm->fields));
4941   dm->fields = NULL;
4942   dm->Nf     = 0;
4943   PetscFunctionReturn(PETSC_SUCCESS);
4944 }
4945 
4946 /*@
4947   DMGetNumFields - Get the number of fields in the `DM`
4948 
4949   Not Collective
4950 
4951   Input Parameter:
4952 . dm - The `DM`
4953 
4954   Output Parameter:
4955 . numFields - The number of fields
4956 
4957   Level: intermediate
4958 
4959 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4960 @*/
4961 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4962 {
4963   PetscFunctionBegin;
4964   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4965   PetscAssertPointer(numFields, 2);
4966   *numFields = dm->Nf;
4967   PetscFunctionReturn(PETSC_SUCCESS);
4968 }
4969 
4970 /*@
4971   DMSetNumFields - Set the number of fields in the `DM`
4972 
4973   Logically Collective
4974 
4975   Input Parameters:
4976 + dm        - The `DM`
4977 - numFields - The number of fields
4978 
4979   Level: intermediate
4980 
4981 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
4982 @*/
4983 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4984 {
4985   PetscInt Nf, f;
4986 
4987   PetscFunctionBegin;
4988   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4989   PetscCall(DMGetNumFields(dm, &Nf));
4990   for (f = Nf; f < numFields; ++f) {
4991     PetscContainer obj;
4992 
4993     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
4994     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
4995     PetscCall(PetscContainerDestroy(&obj));
4996   }
4997   PetscFunctionReturn(PETSC_SUCCESS);
4998 }
4999 
5000 /*@
5001   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
5002 
5003   Not Collective
5004 
5005   Input Parameters:
5006 + dm - The `DM`
5007 - f  - The field number
5008 
5009   Output Parameters:
5010 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
5011 - disc  - The discretization object (pass in `NULL` if not needed)
5012 
5013   Level: intermediate
5014 
5015 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
5016 @*/
5017 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
5018 {
5019   PetscFunctionBegin;
5020   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5021   PetscAssertPointer(disc, 4);
5022   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);
5023   if (label) *label = dm->fields[f].label;
5024   if (disc) *disc = dm->fields[f].disc;
5025   PetscFunctionReturn(PETSC_SUCCESS);
5026 }
5027 
5028 /* Does not clear the DS */
5029 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5030 {
5031   PetscFunctionBegin;
5032   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
5033   PetscCall(DMLabelDestroy(&dm->fields[f].label));
5034   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
5035   dm->fields[f].label = label;
5036   dm->fields[f].disc  = disc;
5037   PetscCall(PetscObjectReference((PetscObject)label));
5038   PetscCall(PetscObjectReference(disc));
5039   PetscFunctionReturn(PETSC_SUCCESS);
5040 }
5041 
5042 /*@
5043   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
5044   the field numbering.
5045 
5046   Logically Collective
5047 
5048   Input Parameters:
5049 + dm    - The `DM`
5050 . f     - The field number
5051 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5052 - disc  - The discretization object
5053 
5054   Level: intermediate
5055 
5056 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
5057 @*/
5058 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5059 {
5060   PetscFunctionBegin;
5061   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5062   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5063   PetscValidHeader(disc, 4);
5064   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
5065   PetscCall(DMSetField_Internal(dm, f, label, disc));
5066   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
5067   PetscCall(DMClearDS(dm));
5068   PetscFunctionReturn(PETSC_SUCCESS);
5069 }
5070 
5071 /*@
5072   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
5073   and a discretization object that defines the function space associated with those points.
5074 
5075   Logically Collective
5076 
5077   Input Parameters:
5078 + dm    - The `DM`
5079 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5080 - disc  - The discretization object
5081 
5082   Level: intermediate
5083 
5084   Notes:
5085   The label already exists or will be added to the `DM` with `DMSetLabel()`.
5086 
5087   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
5088   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
5089   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5090 
5091 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5092 @*/
5093 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5094 {
5095   PetscInt Nf = dm->Nf;
5096 
5097   PetscFunctionBegin;
5098   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5099   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5100   PetscValidHeader(disc, 3);
5101   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5102   dm->fields[Nf].label = label;
5103   dm->fields[Nf].disc  = disc;
5104   PetscCall(PetscObjectReference((PetscObject)label));
5105   PetscCall(PetscObjectReference(disc));
5106   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5107   PetscCall(DMClearDS(dm));
5108   PetscFunctionReturn(PETSC_SUCCESS);
5109 }
5110 
5111 /*@
5112   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5113 
5114   Logically Collective
5115 
5116   Input Parameters:
5117 + dm          - The `DM`
5118 . f           - The field index
5119 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5120 
5121   Level: intermediate
5122 
5123 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5124 @*/
5125 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5126 {
5127   PetscFunctionBegin;
5128   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);
5129   dm->fields[f].avoidTensor = avoidTensor;
5130   PetscFunctionReturn(PETSC_SUCCESS);
5131 }
5132 
5133 /*@
5134   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5135 
5136   Not Collective
5137 
5138   Input Parameters:
5139 + dm - The `DM`
5140 - f  - The field index
5141 
5142   Output Parameter:
5143 . avoidTensor - The flag to avoid defining the field on tensor cells
5144 
5145   Level: intermediate
5146 
5147 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5148 @*/
5149 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5150 {
5151   PetscFunctionBegin;
5152   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);
5153   *avoidTensor = dm->fields[f].avoidTensor;
5154   PetscFunctionReturn(PETSC_SUCCESS);
5155 }
5156 
5157 /*@
5158   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5159 
5160   Collective
5161 
5162   Input Parameters:
5163 + dm        - The `DM`
5164 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
5165 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
5166 
5167   Output Parameter:
5168 . newdm - The `DM`
5169 
5170   Level: advanced
5171 
5172 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5173 @*/
5174 PetscErrorCode DMCopyFields(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
5175 {
5176   PetscInt Nf, f;
5177 
5178   PetscFunctionBegin;
5179   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5180   PetscCall(DMGetNumFields(dm, &Nf));
5181   PetscCall(DMClearFields(newdm));
5182   for (f = 0; f < Nf; ++f) {
5183     DMLabel      label;
5184     PetscObject  field;
5185     PetscClassId id;
5186     PetscBool    useCone, useClosure;
5187 
5188     PetscCall(DMGetField(dm, f, &label, &field));
5189     PetscCall(PetscObjectGetClassId(field, &id));
5190     if (id == PETSCFE_CLASSID) {
5191       PetscFE newfe;
5192 
5193       PetscCall(PetscFELimitDegree((PetscFE)field, minDegree, maxDegree, &newfe));
5194       PetscCall(DMSetField(newdm, f, label, (PetscObject)newfe));
5195       PetscCall(PetscFEDestroy(&newfe));
5196     } else {
5197       PetscCall(DMSetField(newdm, f, label, field));
5198     }
5199     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5200     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5201   }
5202   PetscFunctionReturn(PETSC_SUCCESS);
5203 }
5204 
5205 /*@
5206   DMGetAdjacency - Returns the flags for determining variable influence
5207 
5208   Not Collective
5209 
5210   Input Parameters:
5211 + dm - The `DM` object
5212 - f  - The field number, or `PETSC_DEFAULT` for the default adjacency
5213 
5214   Output Parameters:
5215 + useCone    - Flag for variable influence starting with the cone operation
5216 - useClosure - Flag for variable influence using transitive closure
5217 
5218   Level: developer
5219 
5220   Notes:
5221 .vb
5222      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5223      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5224      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5225 .ve
5226   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5227 
5228 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5229 @*/
5230 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5231 {
5232   PetscFunctionBegin;
5233   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5234   if (useCone) PetscAssertPointer(useCone, 3);
5235   if (useClosure) PetscAssertPointer(useClosure, 4);
5236   if (f < 0) {
5237     if (useCone) *useCone = dm->adjacency[0];
5238     if (useClosure) *useClosure = dm->adjacency[1];
5239   } else {
5240     PetscInt Nf;
5241 
5242     PetscCall(DMGetNumFields(dm, &Nf));
5243     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5244     if (useCone) *useCone = dm->fields[f].adjacency[0];
5245     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5246   }
5247   PetscFunctionReturn(PETSC_SUCCESS);
5248 }
5249 
5250 /*@
5251   DMSetAdjacency - Set the flags for determining variable influence
5252 
5253   Not Collective
5254 
5255   Input Parameters:
5256 + dm         - The `DM` object
5257 . f          - The field number
5258 . useCone    - Flag for variable influence starting with the cone operation
5259 - useClosure - Flag for variable influence using transitive closure
5260 
5261   Level: developer
5262 
5263   Notes:
5264 .vb
5265      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5266      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5267      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5268 .ve
5269   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5270 
5271 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5272 @*/
5273 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5274 {
5275   PetscFunctionBegin;
5276   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5277   if (f < 0) {
5278     dm->adjacency[0] = useCone;
5279     dm->adjacency[1] = useClosure;
5280   } else {
5281     PetscInt Nf;
5282 
5283     PetscCall(DMGetNumFields(dm, &Nf));
5284     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5285     dm->fields[f].adjacency[0] = useCone;
5286     dm->fields[f].adjacency[1] = useClosure;
5287   }
5288   PetscFunctionReturn(PETSC_SUCCESS);
5289 }
5290 
5291 /*@
5292   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5293 
5294   Not collective
5295 
5296   Input Parameter:
5297 . dm - The `DM` object
5298 
5299   Output Parameters:
5300 + useCone    - Flag for variable influence starting with the cone operation
5301 - useClosure - Flag for variable influence using transitive closure
5302 
5303   Level: developer
5304 
5305   Notes:
5306 .vb
5307      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5308      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5309      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5310 .ve
5311 
5312 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5313 @*/
5314 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5315 {
5316   PetscInt Nf;
5317 
5318   PetscFunctionBegin;
5319   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5320   if (useCone) PetscAssertPointer(useCone, 2);
5321   if (useClosure) PetscAssertPointer(useClosure, 3);
5322   PetscCall(DMGetNumFields(dm, &Nf));
5323   if (!Nf) {
5324     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5325   } else {
5326     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5327   }
5328   PetscFunctionReturn(PETSC_SUCCESS);
5329 }
5330 
5331 /*@
5332   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5333 
5334   Not Collective
5335 
5336   Input Parameters:
5337 + dm         - The `DM` object
5338 . useCone    - Flag for variable influence starting with the cone operation
5339 - useClosure - Flag for variable influence using transitive closure
5340 
5341   Level: developer
5342 
5343   Notes:
5344 .vb
5345      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5346      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5347      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5348 .ve
5349 
5350 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5351 @*/
5352 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5353 {
5354   PetscInt Nf;
5355 
5356   PetscFunctionBegin;
5357   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5358   PetscCall(DMGetNumFields(dm, &Nf));
5359   if (!Nf) {
5360     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5361   } else {
5362     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5363   }
5364   PetscFunctionReturn(PETSC_SUCCESS);
5365 }
5366 
5367 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5368 {
5369   DM           plex;
5370   DMLabel     *labels, *glabels;
5371   const char **names;
5372   char        *sendNames, *recvNames;
5373   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5374   size_t       len;
5375   MPI_Comm     comm;
5376   PetscMPIInt  rank, size, p, *counts, *displs;
5377 
5378   PetscFunctionBegin;
5379   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5380   PetscCallMPI(MPI_Comm_size(comm, &size));
5381   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5382   PetscCall(DMGetNumDS(dm, &Nds));
5383   for (s = 0; s < Nds; ++s) {
5384     PetscDS  dsBC;
5385     PetscInt numBd;
5386 
5387     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5388     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5389     maxLabels += numBd;
5390   }
5391   PetscCall(PetscCalloc1(maxLabels, &labels));
5392   /* Get list of labels to be completed */
5393   for (s = 0; s < Nds; ++s) {
5394     PetscDS  dsBC;
5395     PetscInt numBd, bd;
5396 
5397     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5398     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5399     for (bd = 0; bd < numBd; ++bd) {
5400       DMLabel      label;
5401       PetscInt     field;
5402       PetscObject  obj;
5403       PetscClassId id;
5404 
5405       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5406       PetscCall(DMGetField(dm, field, NULL, &obj));
5407       PetscCall(PetscObjectGetClassId(obj, &id));
5408       if (!(id == PETSCFE_CLASSID) || !label) continue;
5409       for (l = 0; l < Nl; ++l)
5410         if (labels[l] == label) break;
5411       if (l == Nl) labels[Nl++] = label;
5412     }
5413   }
5414   /* Get label names */
5415   PetscCall(PetscMalloc1(Nl, &names));
5416   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5417   for (l = 0; l < Nl; ++l) {
5418     PetscCall(PetscStrlen(names[l], &len));
5419     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5420   }
5421   PetscCall(PetscFree(labels));
5422   PetscCallMPI(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5423   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5424   for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5425   PetscCall(PetscFree(names));
5426   /* Put all names on all processes */
5427   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5428   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5429   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5430   gNl = displs[size];
5431   for (p = 0; p < size; ++p) {
5432     counts[p] *= gmaxLen;
5433     displs[p] *= gmaxLen;
5434   }
5435   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5436   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5437   PetscCall(PetscFree2(counts, displs));
5438   PetscCall(PetscFree(sendNames));
5439   for (l = 0, gl = 0; l < gNl; ++l) {
5440     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5441     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5442     for (m = 0; m < gl; ++m)
5443       if (glabels[m] == glabels[gl]) goto next_label;
5444     PetscCall(DMConvert(dm, DMPLEX, &plex));
5445     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5446     PetscCall(DMDestroy(&plex));
5447     ++gl;
5448   next_label:
5449     continue;
5450   }
5451   PetscCall(PetscFree2(recvNames, glabels));
5452   PetscFunctionReturn(PETSC_SUCCESS);
5453 }
5454 
5455 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5456 {
5457   DMSpace *tmpd;
5458   PetscInt Nds = dm->Nds, s;
5459 
5460   PetscFunctionBegin;
5461   if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5462   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5463   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5464   for (s = Nds; s < NdsNew; ++s) {
5465     tmpd[s].ds     = NULL;
5466     tmpd[s].label  = NULL;
5467     tmpd[s].fields = NULL;
5468   }
5469   PetscCall(PetscFree(dm->probs));
5470   dm->Nds   = NdsNew;
5471   dm->probs = tmpd;
5472   PetscFunctionReturn(PETSC_SUCCESS);
5473 }
5474 
5475 /*@
5476   DMGetNumDS - Get the number of discrete systems in the `DM`
5477 
5478   Not Collective
5479 
5480   Input Parameter:
5481 . dm - The `DM`
5482 
5483   Output Parameter:
5484 . Nds - The number of `PetscDS` objects
5485 
5486   Level: intermediate
5487 
5488 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5489 @*/
5490 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5491 {
5492   PetscFunctionBegin;
5493   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5494   PetscAssertPointer(Nds, 2);
5495   *Nds = dm->Nds;
5496   PetscFunctionReturn(PETSC_SUCCESS);
5497 }
5498 
5499 /*@
5500   DMClearDS - Remove all discrete systems from the `DM`
5501 
5502   Logically Collective
5503 
5504   Input Parameter:
5505 . dm - The `DM`
5506 
5507   Level: intermediate
5508 
5509 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5510 @*/
5511 PetscErrorCode DMClearDS(DM dm)
5512 {
5513   PetscInt s;
5514 
5515   PetscFunctionBegin;
5516   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5517   for (s = 0; s < dm->Nds; ++s) {
5518     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5519     PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5520     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5521     PetscCall(ISDestroy(&dm->probs[s].fields));
5522   }
5523   PetscCall(PetscFree(dm->probs));
5524   dm->probs = NULL;
5525   dm->Nds   = 0;
5526   PetscFunctionReturn(PETSC_SUCCESS);
5527 }
5528 
5529 /*@
5530   DMGetDS - Get the default `PetscDS`
5531 
5532   Not Collective
5533 
5534   Input Parameter:
5535 . dm - The `DM`
5536 
5537   Output Parameter:
5538 . ds - The default `PetscDS`
5539 
5540   Level: intermediate
5541 
5542 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5543 @*/
5544 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5545 {
5546   PetscFunctionBeginHot;
5547   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5548   PetscAssertPointer(ds, 2);
5549   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5550   *ds = dm->probs[0].ds;
5551   PetscFunctionReturn(PETSC_SUCCESS);
5552 }
5553 
5554 /*@
5555   DMGetCellDS - Get the `PetscDS` defined on a given cell
5556 
5557   Not Collective
5558 
5559   Input Parameters:
5560 + dm    - The `DM`
5561 - point - Cell for the `PetscDS`
5562 
5563   Output Parameters:
5564 + ds   - The `PetscDS` defined on the given cell
5565 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds
5566 
5567   Level: developer
5568 
5569 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5570 @*/
5571 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5572 {
5573   PetscDS  dsDef = NULL;
5574   PetscInt s;
5575 
5576   PetscFunctionBeginHot;
5577   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5578   if (ds) PetscAssertPointer(ds, 3);
5579   if (dsIn) PetscAssertPointer(dsIn, 4);
5580   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5581   if (ds) *ds = NULL;
5582   if (dsIn) *dsIn = NULL;
5583   for (s = 0; s < dm->Nds; ++s) {
5584     PetscInt val;
5585 
5586     if (!dm->probs[s].label) {
5587       dsDef = dm->probs[s].ds;
5588     } else {
5589       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5590       if (val >= 0) {
5591         if (ds) *ds = dm->probs[s].ds;
5592         if (dsIn) *dsIn = dm->probs[s].dsIn;
5593         break;
5594       }
5595     }
5596   }
5597   if (ds && !*ds) *ds = dsDef;
5598   PetscFunctionReturn(PETSC_SUCCESS);
5599 }
5600 
5601 /*@
5602   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5603 
5604   Not Collective
5605 
5606   Input Parameters:
5607 + dm    - The `DM`
5608 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5609 
5610   Output Parameters:
5611 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5612 . ds     - The `PetscDS` defined on the given region, or `NULL`
5613 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5614 
5615   Level: advanced
5616 
5617   Note:
5618   If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5619   the `PetscDS` for the full domain (if present) is returned. Returns with
5620   fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5621 
5622 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5623 @*/
5624 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5625 {
5626   PetscInt Nds = dm->Nds, s;
5627 
5628   PetscFunctionBegin;
5629   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5630   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5631   if (fields) {
5632     PetscAssertPointer(fields, 3);
5633     *fields = NULL;
5634   }
5635   if (ds) {
5636     PetscAssertPointer(ds, 4);
5637     *ds = NULL;
5638   }
5639   if (dsIn) {
5640     PetscAssertPointer(dsIn, 5);
5641     *dsIn = NULL;
5642   }
5643   for (s = 0; s < Nds; ++s) {
5644     if (dm->probs[s].label == label || !dm->probs[s].label) {
5645       if (fields) *fields = dm->probs[s].fields;
5646       if (ds) *ds = dm->probs[s].ds;
5647       if (dsIn) *dsIn = dm->probs[s].dsIn;
5648       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5649     }
5650   }
5651   PetscFunctionReturn(PETSC_SUCCESS);
5652 }
5653 
5654 /*@
5655   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5656 
5657   Collective
5658 
5659   Input Parameters:
5660 + dm     - The `DM`
5661 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5662 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5663 . ds     - The `PetscDS` defined on the given region
5664 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5665 
5666   Level: advanced
5667 
5668   Note:
5669   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5670   the fields argument is ignored.
5671 
5672 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5673 @*/
5674 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5675 {
5676   PetscInt Nds = dm->Nds, s;
5677 
5678   PetscFunctionBegin;
5679   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5680   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5681   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5682   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5683   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5684   for (s = 0; s < Nds; ++s) {
5685     if (dm->probs[s].label == label) {
5686       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5687       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5688       dm->probs[s].ds   = ds;
5689       dm->probs[s].dsIn = dsIn;
5690       PetscFunctionReturn(PETSC_SUCCESS);
5691     }
5692   }
5693   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5694   PetscCall(PetscObjectReference((PetscObject)label));
5695   PetscCall(PetscObjectReference((PetscObject)fields));
5696   PetscCall(PetscObjectReference((PetscObject)ds));
5697   PetscCall(PetscObjectReference((PetscObject)dsIn));
5698   if (!label) {
5699     /* Put the NULL label at the front, so it is returned as the default */
5700     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5701     Nds = 0;
5702   }
5703   dm->probs[Nds].label  = label;
5704   dm->probs[Nds].fields = fields;
5705   dm->probs[Nds].ds     = ds;
5706   dm->probs[Nds].dsIn   = dsIn;
5707   PetscFunctionReturn(PETSC_SUCCESS);
5708 }
5709 
5710 /*@
5711   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5712 
5713   Not Collective
5714 
5715   Input Parameters:
5716 + dm  - The `DM`
5717 - num - The region number, in [0, Nds)
5718 
5719   Output Parameters:
5720 + label  - The region label, or `NULL`
5721 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5722 . ds     - The `PetscDS` defined on the given region, or `NULL`
5723 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5724 
5725   Level: advanced
5726 
5727 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5728 @*/
5729 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5730 {
5731   PetscInt Nds;
5732 
5733   PetscFunctionBegin;
5734   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5735   PetscCall(DMGetNumDS(dm, &Nds));
5736   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5737   if (label) {
5738     PetscAssertPointer(label, 3);
5739     *label = dm->probs[num].label;
5740   }
5741   if (fields) {
5742     PetscAssertPointer(fields, 4);
5743     *fields = dm->probs[num].fields;
5744   }
5745   if (ds) {
5746     PetscAssertPointer(ds, 5);
5747     *ds = dm->probs[num].ds;
5748   }
5749   if (dsIn) {
5750     PetscAssertPointer(dsIn, 6);
5751     *dsIn = dm->probs[num].dsIn;
5752   }
5753   PetscFunctionReturn(PETSC_SUCCESS);
5754 }
5755 
5756 /*@
5757   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5758 
5759   Not Collective
5760 
5761   Input Parameters:
5762 + dm     - The `DM`
5763 . num    - The region number, in [0, Nds)
5764 . label  - The region label, or `NULL`
5765 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5766 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5767 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5768 
5769   Level: advanced
5770 
5771 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5772 @*/
5773 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5774 {
5775   PetscInt Nds;
5776 
5777   PetscFunctionBegin;
5778   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5779   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5780   PetscCall(DMGetNumDS(dm, &Nds));
5781   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5782   PetscCall(PetscObjectReference((PetscObject)label));
5783   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5784   dm->probs[num].label = label;
5785   if (fields) {
5786     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5787     PetscCall(PetscObjectReference((PetscObject)fields));
5788     PetscCall(ISDestroy(&dm->probs[num].fields));
5789     dm->probs[num].fields = fields;
5790   }
5791   if (ds) {
5792     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5793     PetscCall(PetscObjectReference((PetscObject)ds));
5794     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5795     dm->probs[num].ds = ds;
5796   }
5797   if (dsIn) {
5798     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5799     PetscCall(PetscObjectReference((PetscObject)dsIn));
5800     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5801     dm->probs[num].dsIn = dsIn;
5802   }
5803   PetscFunctionReturn(PETSC_SUCCESS);
5804 }
5805 
5806 /*@
5807   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5808 
5809   Not Collective
5810 
5811   Input Parameters:
5812 + dm - The `DM`
5813 - ds - The `PetscDS` defined on the given region
5814 
5815   Output Parameter:
5816 . num - The region number, in [0, Nds), or -1 if not found
5817 
5818   Level: advanced
5819 
5820 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5821 @*/
5822 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5823 {
5824   PetscInt Nds, n;
5825 
5826   PetscFunctionBegin;
5827   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5828   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5829   PetscAssertPointer(num, 3);
5830   PetscCall(DMGetNumDS(dm, &Nds));
5831   for (n = 0; n < Nds; ++n)
5832     if (ds == dm->probs[n].ds) break;
5833   if (n >= Nds) *num = -1;
5834   else *num = n;
5835   PetscFunctionReturn(PETSC_SUCCESS);
5836 }
5837 
5838 /*@
5839   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5840 
5841   Not Collective
5842 
5843   Input Parameters:
5844 + dm     - The `DM`
5845 . Nc     - The number of components for the field
5846 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5847 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5848 
5849   Output Parameter:
5850 . fem - The `PetscFE`
5851 
5852   Level: intermediate
5853 
5854   Note:
5855   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5856 
5857 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5858 @*/
5859 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5860 {
5861   DMPolytopeType ct;
5862   PetscInt       dim, cStart;
5863 
5864   PetscFunctionBegin;
5865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5866   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5867   if (prefix) PetscAssertPointer(prefix, 3);
5868   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5869   PetscAssertPointer(fem, 5);
5870   PetscCall(DMGetDimension(dm, &dim));
5871   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5872   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5873   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5874   PetscFunctionReturn(PETSC_SUCCESS);
5875 }
5876 
5877 /*@
5878   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5879 
5880   Collective
5881 
5882   Input Parameter:
5883 . dm - The `DM`
5884 
5885   Options Database Key:
5886 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5887 
5888   Level: intermediate
5889 
5890 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5891 @*/
5892 PetscErrorCode DMCreateDS(DM dm)
5893 {
5894   MPI_Comm  comm;
5895   PetscDS   dsDef;
5896   DMLabel  *labelSet;
5897   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5898   PetscBool doSetup = PETSC_TRUE, flg;
5899 
5900   PetscFunctionBegin;
5901   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5902   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5903   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5904   PetscCall(DMGetCoordinateDim(dm, &dE));
5905   /* Determine how many regions we have */
5906   PetscCall(PetscMalloc1(Nf, &labelSet));
5907   Nl   = 0;
5908   Ndef = 0;
5909   for (f = 0; f < Nf; ++f) {
5910     DMLabel  label = dm->fields[f].label;
5911     PetscInt l;
5912 
5913 #ifdef PETSC_HAVE_LIBCEED
5914     /* Move CEED context to discretizations */
5915     {
5916       PetscClassId id;
5917 
5918       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5919       if (id == PETSCFE_CLASSID) {
5920         Ceed ceed;
5921 
5922         PetscCall(DMGetCeed(dm, &ceed));
5923         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5924       }
5925     }
5926 #endif
5927     if (!label) {
5928       ++Ndef;
5929       continue;
5930     }
5931     for (l = 0; l < Nl; ++l)
5932       if (label == labelSet[l]) break;
5933     if (l < Nl) continue;
5934     labelSet[Nl++] = label;
5935   }
5936   /* Create default DS if there are no labels to intersect with */
5937   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5938   if (!dsDef && Ndef && !Nl) {
5939     IS        fields;
5940     PetscInt *fld, nf;
5941 
5942     for (f = 0, nf = 0; f < Nf; ++f)
5943       if (!dm->fields[f].label) ++nf;
5944     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5945     PetscCall(PetscMalloc1(nf, &fld));
5946     for (f = 0, nf = 0; f < Nf; ++f)
5947       if (!dm->fields[f].label) fld[nf++] = f;
5948     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5949     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5950     PetscCall(ISSetType(fields, ISGENERAL));
5951     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5952 
5953     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5954     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5955     PetscCall(PetscDSDestroy(&dsDef));
5956     PetscCall(ISDestroy(&fields));
5957   }
5958   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5959   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5960   /* Intersect labels with default fields */
5961   if (Ndef && Nl) {
5962     DM              plex;
5963     DMLabel         cellLabel;
5964     IS              fieldIS, allcellIS, defcellIS = NULL;
5965     PetscInt       *fields;
5966     const PetscInt *cells;
5967     PetscInt        depth, nf = 0, n, c;
5968 
5969     PetscCall(DMConvert(dm, DMPLEX, &plex));
5970     PetscCall(DMPlexGetDepth(plex, &depth));
5971     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5972     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5973     /* TODO This looks like it only works for one label */
5974     for (l = 0; l < Nl; ++l) {
5975       DMLabel label = labelSet[l];
5976       IS      pointIS;
5977 
5978       PetscCall(ISDestroy(&defcellIS));
5979       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5980       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5981       PetscCall(ISDestroy(&pointIS));
5982     }
5983     PetscCall(ISDestroy(&allcellIS));
5984 
5985     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5986     PetscCall(ISGetLocalSize(defcellIS, &n));
5987     PetscCall(ISGetIndices(defcellIS, &cells));
5988     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5989     PetscCall(ISRestoreIndices(defcellIS, &cells));
5990     PetscCall(ISDestroy(&defcellIS));
5991     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5992 
5993     PetscCall(PetscMalloc1(Ndef, &fields));
5994     for (f = 0; f < Nf; ++f)
5995       if (!dm->fields[f].label) fields[nf++] = f;
5996     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
5997     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
5998     PetscCall(ISSetType(fieldIS, ISGENERAL));
5999     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
6000 
6001     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
6002     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
6003     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6004     PetscCall(DMLabelDestroy(&cellLabel));
6005     PetscCall(PetscDSDestroy(&dsDef));
6006     PetscCall(ISDestroy(&fieldIS));
6007     PetscCall(DMDestroy(&plex));
6008   }
6009   /* Create label DSes
6010      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
6011   */
6012   /* TODO Should check that labels are disjoint */
6013   for (l = 0; l < Nl; ++l) {
6014     DMLabel   label = labelSet[l];
6015     PetscDS   ds, dsIn = NULL;
6016     IS        fields;
6017     PetscInt *fld, nf;
6018 
6019     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
6020     for (f = 0, nf = 0; f < Nf; ++f)
6021       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
6022     PetscCall(PetscMalloc1(nf, &fld));
6023     for (f = 0, nf = 0; f < Nf; ++f)
6024       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
6025     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
6026     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
6027     PetscCall(ISSetType(fields, ISGENERAL));
6028     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
6029     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
6030     {
6031       DMPolytopeType ct;
6032       PetscInt       lStart, lEnd;
6033       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
6034 
6035       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
6036       if (lStart >= 0) {
6037         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
6038         switch (ct) {
6039         case DM_POLYTOPE_POINT_PRISM_TENSOR:
6040         case DM_POLYTOPE_SEG_PRISM_TENSOR:
6041         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6042         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
6043           isCohesiveLocal = PETSC_TRUE;
6044           break;
6045         default:
6046           break;
6047         }
6048       }
6049       PetscCallMPI(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
6050       if (isCohesive) {
6051         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
6052         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
6053       }
6054       for (f = 0, nf = 0; f < Nf; ++f) {
6055         if (label == dm->fields[f].label || !dm->fields[f].label) {
6056           if (label == dm->fields[f].label) {
6057             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
6058             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
6059             if (dsIn) {
6060               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
6061               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
6062             }
6063           }
6064           ++nf;
6065         }
6066       }
6067     }
6068     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
6069     PetscCall(ISDestroy(&fields));
6070     PetscCall(PetscDSDestroy(&ds));
6071     PetscCall(PetscDSDestroy(&dsIn));
6072   }
6073   PetscCall(PetscFree(labelSet));
6074   /* Set fields in DSes */
6075   for (s = 0; s < dm->Nds; ++s) {
6076     PetscDS         ds     = dm->probs[s].ds;
6077     PetscDS         dsIn   = dm->probs[s].dsIn;
6078     IS              fields = dm->probs[s].fields;
6079     const PetscInt *fld;
6080     PetscInt        nf, dsnf;
6081     PetscBool       isCohesive;
6082 
6083     PetscCall(PetscDSGetNumFields(ds, &dsnf));
6084     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
6085     PetscCall(ISGetLocalSize(fields, &nf));
6086     PetscCall(ISGetIndices(fields, &fld));
6087     for (f = 0; f < nf; ++f) {
6088       PetscObject  disc = dm->fields[fld[f]].disc;
6089       PetscBool    isCohesiveField;
6090       PetscClassId id;
6091 
6092       /* Handle DS with no fields */
6093       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
6094       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
6095       if (isCohesive) {
6096         if (!isCohesiveField) {
6097           PetscObject bdDisc;
6098 
6099           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
6100           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
6101           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6102         } else {
6103           PetscCall(PetscDSSetDiscretization(ds, f, disc));
6104           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6105         }
6106       } else {
6107         PetscCall(PetscDSSetDiscretization(ds, f, disc));
6108       }
6109       /* We allow people to have placeholder fields and construct the Section by hand */
6110       PetscCall(PetscObjectGetClassId(disc, &id));
6111       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
6112     }
6113     PetscCall(ISRestoreIndices(fields, &fld));
6114   }
6115   /* Allow k-jet tabulation */
6116   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6117   if (flg) {
6118     for (s = 0; s < dm->Nds; ++s) {
6119       PetscDS  ds   = dm->probs[s].ds;
6120       PetscDS  dsIn = dm->probs[s].dsIn;
6121       PetscInt Nf, f;
6122 
6123       PetscCall(PetscDSGetNumFields(ds, &Nf));
6124       for (f = 0; f < Nf; ++f) {
6125         PetscCall(PetscDSSetJetDegree(ds, f, k));
6126         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6127       }
6128     }
6129   }
6130   /* Setup DSes */
6131   if (doSetup) {
6132     for (s = 0; s < dm->Nds; ++s) {
6133       if (dm->setfromoptionscalled) {
6134         PetscCall(PetscDSSetFromOptions(dm->probs[s].ds));
6135         if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn));
6136       }
6137       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6138       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6139     }
6140   }
6141   PetscFunctionReturn(PETSC_SUCCESS);
6142 }
6143 
6144 /*@
6145   DMUseTensorOrder - Use a tensor product closure ordering for the default section
6146 
6147   Input Parameters:
6148 + dm     - The DM
6149 - tensor - Flag for tensor order
6150 
6151   Level: developer
6152 
6153 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()`
6154 @*/
6155 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor)
6156 {
6157   PetscInt  Nf;
6158   PetscBool reorder = PETSC_TRUE, isPlex;
6159 
6160   PetscFunctionBegin;
6161   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
6162   PetscCall(DMGetNumFields(dm, &Nf));
6163   for (PetscInt f = 0; f < Nf; ++f) {
6164     PetscObject  obj;
6165     PetscClassId id;
6166 
6167     PetscCall(DMGetField(dm, f, NULL, &obj));
6168     PetscCall(PetscObjectGetClassId(obj, &id));
6169     if (id == PETSCFE_CLASSID) {
6170       PetscSpace sp;
6171       PetscBool  tensor;
6172 
6173       PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp));
6174       PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor));
6175       reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE;
6176     } else reorder = PETSC_FALSE;
6177   }
6178   if (tensor) {
6179     if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
6180   } else {
6181     PetscSection s;
6182 
6183     PetscCall(DMGetLocalSection(dm, &s));
6184     if (s) PetscCall(PetscSectionResetClosurePermutation(s));
6185   }
6186   PetscFunctionReturn(PETSC_SUCCESS);
6187 }
6188 
6189 /*@
6190   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6191 
6192   Collective
6193 
6194   Input Parameters:
6195 + dm   - The `DM`
6196 - time - The time
6197 
6198   Output Parameters:
6199 + u   - The vector will be filled with exact solution values, or `NULL`
6200 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6201 
6202   Level: developer
6203 
6204   Note:
6205   The user must call `PetscDSSetExactSolution()` before using this routine
6206 
6207 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6208 @*/
6209 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6210 {
6211   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6212   void   **ectxs;
6213   Vec      locu, locu_t;
6214   PetscInt Nf, Nds, s;
6215 
6216   PetscFunctionBegin;
6217   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6218   if (u) {
6219     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6220     PetscCall(DMGetLocalVector(dm, &locu));
6221     PetscCall(VecSet(locu, 0.));
6222   }
6223   if (u_t) {
6224     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6225     PetscCall(DMGetLocalVector(dm, &locu_t));
6226     PetscCall(VecSet(locu_t, 0.));
6227   }
6228   PetscCall(DMGetNumFields(dm, &Nf));
6229   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6230   PetscCall(DMGetNumDS(dm, &Nds));
6231   for (s = 0; s < Nds; ++s) {
6232     PetscDS         ds;
6233     DMLabel         label;
6234     IS              fieldIS;
6235     const PetscInt *fields, id = 1;
6236     PetscInt        dsNf, f;
6237 
6238     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6239     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6240     PetscCall(ISGetIndices(fieldIS, &fields));
6241     PetscCall(PetscArrayzero(exacts, Nf));
6242     PetscCall(PetscArrayzero(ectxs, Nf));
6243     if (u) {
6244       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6245       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6246       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6247     }
6248     if (u_t) {
6249       PetscCall(PetscArrayzero(exacts, Nf));
6250       PetscCall(PetscArrayzero(ectxs, Nf));
6251       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6252       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6253       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6254     }
6255     PetscCall(ISRestoreIndices(fieldIS, &fields));
6256   }
6257   if (u) {
6258     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6259     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6260   }
6261   if (u_t) {
6262     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6263     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6264   }
6265   PetscCall(PetscFree2(exacts, ectxs));
6266   if (u) {
6267     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6268     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6269     PetscCall(DMRestoreLocalVector(dm, &locu));
6270   }
6271   if (u_t) {
6272     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6273     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6274     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6275   }
6276   PetscFunctionReturn(PETSC_SUCCESS);
6277 }
6278 
6279 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscInt minDegree, PetscInt maxDegree, PetscDS ds, PetscDS dsIn)
6280 {
6281   PetscDS dsNew, dsInNew = NULL;
6282 
6283   PetscFunctionBegin;
6284   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6285   PetscCall(PetscDSCopy(ds, minDegree, maxDegree, dm, dsNew));
6286   if (dsIn) {
6287     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6288     PetscCall(PetscDSCopy(dsIn, minDegree, maxDegree, dm, dsInNew));
6289   }
6290   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6291   PetscCall(PetscDSDestroy(&dsNew));
6292   PetscCall(PetscDSDestroy(&dsInNew));
6293   PetscFunctionReturn(PETSC_SUCCESS);
6294 }
6295 
6296 /*@
6297   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6298 
6299   Collective
6300 
6301   Input Parameters:
6302 + dm        - The `DM`
6303 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
6304 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
6305 
6306   Output Parameter:
6307 . newdm - The `DM`
6308 
6309   Level: advanced
6310 
6311 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6312 @*/
6313 PetscErrorCode DMCopyDS(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
6314 {
6315   PetscInt Nds, s;
6316 
6317   PetscFunctionBegin;
6318   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6319   PetscCall(DMGetNumDS(dm, &Nds));
6320   PetscCall(DMClearDS(newdm));
6321   for (s = 0; s < Nds; ++s) {
6322     DMLabel  label;
6323     IS       fields;
6324     PetscDS  ds, dsIn, newds;
6325     PetscInt Nbd, bd;
6326 
6327     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6328     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6329     PetscCall(DMTransferDS_Internal(newdm, label, fields, minDegree, maxDegree, ds, dsIn));
6330     /* Complete new labels in the new DS */
6331     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6332     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6333     for (bd = 0; bd < Nbd; ++bd) {
6334       PetscWeakForm wf;
6335       DMLabel       label;
6336       PetscInt      field;
6337 
6338       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6339       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6340     }
6341   }
6342   PetscCall(DMCompleteBCLabels_Internal(newdm));
6343   PetscFunctionReturn(PETSC_SUCCESS);
6344 }
6345 
6346 /*@
6347   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6348 
6349   Collective
6350 
6351   Input Parameter:
6352 . dm - The `DM`
6353 
6354   Output Parameter:
6355 . newdm - The `DM`
6356 
6357   Level: advanced
6358 
6359   Developer Note:
6360   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6361 
6362 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6363 @*/
6364 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6365 {
6366   PetscFunctionBegin;
6367   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6368   PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6369   PetscFunctionReturn(PETSC_SUCCESS);
6370 }
6371 
6372 /*@
6373   DMGetDimension - Return the topological dimension of the `DM`
6374 
6375   Not Collective
6376 
6377   Input Parameter:
6378 . dm - The `DM`
6379 
6380   Output Parameter:
6381 . dim - The topological dimension
6382 
6383   Level: beginner
6384 
6385 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6386 @*/
6387 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6388 {
6389   PetscFunctionBegin;
6390   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6391   PetscAssertPointer(dim, 2);
6392   *dim = dm->dim;
6393   PetscFunctionReturn(PETSC_SUCCESS);
6394 }
6395 
6396 /*@
6397   DMSetDimension - Set the topological dimension of the `DM`
6398 
6399   Collective
6400 
6401   Input Parameters:
6402 + dm  - The `DM`
6403 - dim - The topological dimension
6404 
6405   Level: beginner
6406 
6407 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6408 @*/
6409 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6410 {
6411   PetscDS  ds;
6412   PetscInt Nds, n;
6413 
6414   PetscFunctionBegin;
6415   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6416   PetscValidLogicalCollectiveInt(dm, dim, 2);
6417   dm->dim = dim;
6418   if (dm->dim >= 0) {
6419     PetscCall(DMGetNumDS(dm, &Nds));
6420     for (n = 0; n < Nds; ++n) {
6421       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6422       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6423     }
6424   }
6425   PetscFunctionReturn(PETSC_SUCCESS);
6426 }
6427 
6428 /*@
6429   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6430 
6431   Collective
6432 
6433   Input Parameters:
6434 + dm  - the `DM`
6435 - dim - the dimension
6436 
6437   Output Parameters:
6438 + pStart - The first point of the given dimension
6439 - pEnd   - The first point following points of the given dimension
6440 
6441   Level: intermediate
6442 
6443   Note:
6444   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6445   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6446   then the interval is empty.
6447 
6448 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6449 @*/
6450 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6451 {
6452   PetscInt d;
6453 
6454   PetscFunctionBegin;
6455   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6456   PetscCall(DMGetDimension(dm, &d));
6457   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6458   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6459   PetscFunctionReturn(PETSC_SUCCESS);
6460 }
6461 
6462 /*@
6463   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6464 
6465   Collective
6466 
6467   Input Parameter:
6468 . dm - The original `DM`
6469 
6470   Output Parameter:
6471 . odm - The `DM` which provides the layout for output
6472 
6473   Level: intermediate
6474 
6475   Note:
6476   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6477   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6478   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6479 
6480 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6481 @*/
6482 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6483 {
6484   PetscSection section;
6485   IS           perm;
6486   PetscBool    hasConstraints, newDM, gnewDM;
6487 
6488   PetscFunctionBegin;
6489   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6490   PetscAssertPointer(odm, 2);
6491   PetscCall(DMGetLocalSection(dm, &section));
6492   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6493   PetscCall(PetscSectionGetPermutation(section, &perm));
6494   newDM = hasConstraints || perm ? PETSC_TRUE : PETSC_FALSE;
6495   PetscCallMPI(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6496   if (!gnewDM) {
6497     *odm = dm;
6498     PetscFunctionReturn(PETSC_SUCCESS);
6499   }
6500   if (!dm->dmBC) {
6501     PetscSection newSection, gsection;
6502     PetscSF      sf;
6503     PetscBool    usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE;
6504 
6505     PetscCall(DMClone(dm, &dm->dmBC));
6506     PetscCall(DMCopyDisc(dm, dm->dmBC));
6507     PetscCall(PetscSectionClone(section, &newSection));
6508     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6509     PetscCall(PetscSectionDestroy(&newSection));
6510     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6511     PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection));
6512     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6513     PetscCall(PetscSectionDestroy(&gsection));
6514   }
6515   *odm = dm->dmBC;
6516   PetscFunctionReturn(PETSC_SUCCESS);
6517 }
6518 
6519 /*@
6520   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6521 
6522   Input Parameter:
6523 . dm - The original `DM`
6524 
6525   Output Parameters:
6526 + num - The output sequence number
6527 - val - The output sequence value
6528 
6529   Level: intermediate
6530 
6531   Note:
6532   This is intended for output that should appear in sequence, for instance
6533   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6534 
6535   Developer Note:
6536   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6537   not directly related to the `DM`.
6538 
6539 .seealso: [](ch_dmbase), `DM`, `VecView()`
6540 @*/
6541 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6542 {
6543   PetscFunctionBegin;
6544   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6545   if (num) {
6546     PetscAssertPointer(num, 2);
6547     *num = dm->outputSequenceNum;
6548   }
6549   if (val) {
6550     PetscAssertPointer(val, 3);
6551     *val = dm->outputSequenceVal;
6552   }
6553   PetscFunctionReturn(PETSC_SUCCESS);
6554 }
6555 
6556 /*@
6557   DMSetOutputSequenceNumber - Set the sequence number/value for output
6558 
6559   Input Parameters:
6560 + dm  - The original `DM`
6561 . num - The output sequence number
6562 - val - The output sequence value
6563 
6564   Level: intermediate
6565 
6566   Note:
6567   This is intended for output that should appear in sequence, for instance
6568   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6569 
6570 .seealso: [](ch_dmbase), `DM`, `VecView()`
6571 @*/
6572 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6573 {
6574   PetscFunctionBegin;
6575   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6576   dm->outputSequenceNum = num;
6577   dm->outputSequenceVal = val;
6578   PetscFunctionReturn(PETSC_SUCCESS);
6579 }
6580 
6581 /*@
6582   DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6583 
6584   Input Parameters:
6585 + dm     - The original `DM`
6586 . viewer - The `PetscViewer` to get it from
6587 . name   - The sequence name
6588 - num    - The output sequence number
6589 
6590   Output Parameter:
6591 . val - The output sequence value
6592 
6593   Level: intermediate
6594 
6595   Note:
6596   This is intended for output that should appear in sequence, for instance
6597   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6598 
6599   Developer Note:
6600   It is unclear at the user API level why a `DM` is needed as input
6601 
6602 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6603 @*/
6604 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val)
6605 {
6606   PetscBool ishdf5;
6607 
6608   PetscFunctionBegin;
6609   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6610   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6611   PetscAssertPointer(name, 3);
6612   PetscAssertPointer(val, 5);
6613   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6614   if (ishdf5) {
6615 #if defined(PETSC_HAVE_HDF5)
6616     PetscScalar value;
6617 
6618     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6619     *val = PetscRealPart(value);
6620 #endif
6621   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6622   PetscFunctionReturn(PETSC_SUCCESS);
6623 }
6624 
6625 /*@
6626   DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer`
6627 
6628   Input Parameters:
6629 + dm     - The original `DM`
6630 . viewer - The `PetscViewer` to get it from
6631 - name   - The sequence name
6632 
6633   Output Parameter:
6634 . len - The length of the output sequence
6635 
6636   Level: intermediate
6637 
6638   Note:
6639   This is intended for output that should appear in sequence, for instance
6640   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6641 
6642   Developer Note:
6643   It is unclear at the user API level why a `DM` is needed as input
6644 
6645 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6646 @*/
6647 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len)
6648 {
6649   PetscBool ishdf5;
6650 
6651   PetscFunctionBegin;
6652   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6653   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6654   PetscAssertPointer(name, 3);
6655   PetscAssertPointer(len, 4);
6656   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6657   if (ishdf5) {
6658 #if defined(PETSC_HAVE_HDF5)
6659     PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer));
6660 #endif
6661   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6662   PetscFunctionReturn(PETSC_SUCCESS);
6663 }
6664 
6665 /*@
6666   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6667 
6668   Not Collective
6669 
6670   Input Parameter:
6671 . dm - The `DM`
6672 
6673   Output Parameter:
6674 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6675 
6676   Level: beginner
6677 
6678 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6679 @*/
6680 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6681 {
6682   PetscFunctionBegin;
6683   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6684   PetscAssertPointer(useNatural, 2);
6685   *useNatural = dm->useNatural;
6686   PetscFunctionReturn(PETSC_SUCCESS);
6687 }
6688 
6689 /*@
6690   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6691 
6692   Collective
6693 
6694   Input Parameters:
6695 + dm         - The `DM`
6696 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6697 
6698   Level: beginner
6699 
6700   Note:
6701   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6702 
6703 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6704 @*/
6705 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6706 {
6707   PetscFunctionBegin;
6708   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6709   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6710   dm->useNatural = useNatural;
6711   PetscFunctionReturn(PETSC_SUCCESS);
6712 }
6713 
6714 /*@
6715   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6716 
6717   Not Collective
6718 
6719   Input Parameters:
6720 + dm   - The `DM` object
6721 - name - The label name
6722 
6723   Level: intermediate
6724 
6725 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6726 @*/
6727 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6728 {
6729   PetscBool flg;
6730   DMLabel   label;
6731 
6732   PetscFunctionBegin;
6733   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6734   PetscAssertPointer(name, 2);
6735   PetscCall(DMHasLabel(dm, name, &flg));
6736   if (!flg) {
6737     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6738     PetscCall(DMAddLabel(dm, label));
6739     PetscCall(DMLabelDestroy(&label));
6740   }
6741   PetscFunctionReturn(PETSC_SUCCESS);
6742 }
6743 
6744 /*@
6745   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6746 
6747   Not Collective
6748 
6749   Input Parameters:
6750 + dm   - The `DM` object
6751 . l    - The index for the label
6752 - name - The label name
6753 
6754   Level: intermediate
6755 
6756 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6757 @*/
6758 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6759 {
6760   DMLabelLink orig, prev = NULL;
6761   DMLabel     label;
6762   PetscInt    Nl, m;
6763   PetscBool   flg, match;
6764   const char *lname;
6765 
6766   PetscFunctionBegin;
6767   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6768   PetscAssertPointer(name, 3);
6769   PetscCall(DMHasLabel(dm, name, &flg));
6770   if (!flg) {
6771     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6772     PetscCall(DMAddLabel(dm, label));
6773     PetscCall(DMLabelDestroy(&label));
6774   }
6775   PetscCall(DMGetNumLabels(dm, &Nl));
6776   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6777   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6778     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6779     PetscCall(PetscStrcmp(name, lname, &match));
6780     if (match) break;
6781   }
6782   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6783   if (!m) dm->labels = orig->next;
6784   else prev->next = orig->next;
6785   if (!l) {
6786     orig->next = dm->labels;
6787     dm->labels = orig;
6788   } else {
6789     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next);
6790     orig->next = prev->next;
6791     prev->next = orig;
6792   }
6793   PetscFunctionReturn(PETSC_SUCCESS);
6794 }
6795 
6796 /*@
6797   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6798 
6799   Not Collective
6800 
6801   Input Parameters:
6802 + dm    - The `DM` object
6803 . name  - The label name
6804 - point - The mesh point
6805 
6806   Output Parameter:
6807 . value - The label value for this point, or -1 if the point is not in the label
6808 
6809   Level: beginner
6810 
6811 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6812 @*/
6813 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6814 {
6815   DMLabel label;
6816 
6817   PetscFunctionBegin;
6818   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6819   PetscAssertPointer(name, 2);
6820   PetscCall(DMGetLabel(dm, name, &label));
6821   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6822   PetscCall(DMLabelGetValue(label, point, value));
6823   PetscFunctionReturn(PETSC_SUCCESS);
6824 }
6825 
6826 /*@
6827   DMSetLabelValue - Add a point to a `DMLabel` with given value
6828 
6829   Not Collective
6830 
6831   Input Parameters:
6832 + dm    - The `DM` object
6833 . name  - The label name
6834 . point - The mesh point
6835 - value - The label value for this point
6836 
6837   Output Parameter:
6838 
6839   Level: beginner
6840 
6841 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6842 @*/
6843 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6844 {
6845   DMLabel label;
6846 
6847   PetscFunctionBegin;
6848   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6849   PetscAssertPointer(name, 2);
6850   PetscCall(DMGetLabel(dm, name, &label));
6851   if (!label) {
6852     PetscCall(DMCreateLabel(dm, name));
6853     PetscCall(DMGetLabel(dm, name, &label));
6854   }
6855   PetscCall(DMLabelSetValue(label, point, value));
6856   PetscFunctionReturn(PETSC_SUCCESS);
6857 }
6858 
6859 /*@
6860   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6861 
6862   Not Collective
6863 
6864   Input Parameters:
6865 + dm    - The `DM` object
6866 . name  - The label name
6867 . point - The mesh point
6868 - value - The label value for this point
6869 
6870   Level: beginner
6871 
6872 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6873 @*/
6874 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6875 {
6876   DMLabel label;
6877 
6878   PetscFunctionBegin;
6879   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6880   PetscAssertPointer(name, 2);
6881   PetscCall(DMGetLabel(dm, name, &label));
6882   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6883   PetscCall(DMLabelClearValue(label, point, value));
6884   PetscFunctionReturn(PETSC_SUCCESS);
6885 }
6886 
6887 /*@
6888   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6889 
6890   Not Collective
6891 
6892   Input Parameters:
6893 + dm   - The `DM` object
6894 - name - The label name
6895 
6896   Output Parameter:
6897 . size - The number of different integer ids, or 0 if the label does not exist
6898 
6899   Level: beginner
6900 
6901   Developer Note:
6902   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6903 
6904 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6905 @*/
6906 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6907 {
6908   DMLabel label;
6909 
6910   PetscFunctionBegin;
6911   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6912   PetscAssertPointer(name, 2);
6913   PetscAssertPointer(size, 3);
6914   PetscCall(DMGetLabel(dm, name, &label));
6915   *size = 0;
6916   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6917   PetscCall(DMLabelGetNumValues(label, size));
6918   PetscFunctionReturn(PETSC_SUCCESS);
6919 }
6920 
6921 /*@
6922   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6923 
6924   Not Collective
6925 
6926   Input Parameters:
6927 + dm   - The `DM` object
6928 - name - The label name
6929 
6930   Output Parameter:
6931 . ids - The integer ids, or `NULL` if the label does not exist
6932 
6933   Level: beginner
6934 
6935 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6936 @*/
6937 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6938 {
6939   DMLabel label;
6940 
6941   PetscFunctionBegin;
6942   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6943   PetscAssertPointer(name, 2);
6944   PetscAssertPointer(ids, 3);
6945   PetscCall(DMGetLabel(dm, name, &label));
6946   *ids = NULL;
6947   if (label) {
6948     PetscCall(DMLabelGetValueIS(label, ids));
6949   } else {
6950     /* returning an empty IS */
6951     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6952   }
6953   PetscFunctionReturn(PETSC_SUCCESS);
6954 }
6955 
6956 /*@
6957   DMGetStratumSize - Get the number of points in a label stratum
6958 
6959   Not Collective
6960 
6961   Input Parameters:
6962 + dm    - The `DM` object
6963 . name  - The label name of the stratum
6964 - value - The stratum value
6965 
6966   Output Parameter:
6967 . size - The number of points, also called the stratum size
6968 
6969   Level: beginner
6970 
6971 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6972 @*/
6973 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6974 {
6975   DMLabel label;
6976 
6977   PetscFunctionBegin;
6978   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6979   PetscAssertPointer(name, 2);
6980   PetscAssertPointer(size, 4);
6981   PetscCall(DMGetLabel(dm, name, &label));
6982   *size = 0;
6983   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6984   PetscCall(DMLabelGetStratumSize(label, value, size));
6985   PetscFunctionReturn(PETSC_SUCCESS);
6986 }
6987 
6988 /*@
6989   DMGetStratumIS - Get the points in a label stratum
6990 
6991   Not Collective
6992 
6993   Input Parameters:
6994 + dm    - The `DM` object
6995 . name  - The label name
6996 - value - The stratum value
6997 
6998   Output Parameter:
6999 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
7000 
7001   Level: beginner
7002 
7003 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
7004 @*/
7005 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7006 {
7007   DMLabel label;
7008 
7009   PetscFunctionBegin;
7010   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7011   PetscAssertPointer(name, 2);
7012   PetscAssertPointer(points, 4);
7013   PetscCall(DMGetLabel(dm, name, &label));
7014   *points = NULL;
7015   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7016   PetscCall(DMLabelGetStratumIS(label, value, points));
7017   PetscFunctionReturn(PETSC_SUCCESS);
7018 }
7019 
7020 /*@
7021   DMSetStratumIS - Set the points in a label stratum
7022 
7023   Not Collective
7024 
7025   Input Parameters:
7026 + dm     - The `DM` object
7027 . name   - The label name
7028 . value  - The stratum value
7029 - points - The stratum points
7030 
7031   Level: beginner
7032 
7033 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
7034 @*/
7035 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7036 {
7037   DMLabel label;
7038 
7039   PetscFunctionBegin;
7040   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7041   PetscAssertPointer(name, 2);
7042   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
7043   PetscCall(DMGetLabel(dm, name, &label));
7044   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7045   PetscCall(DMLabelSetStratumIS(label, value, points));
7046   PetscFunctionReturn(PETSC_SUCCESS);
7047 }
7048 
7049 /*@
7050   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
7051 
7052   Not Collective
7053 
7054   Input Parameters:
7055 + dm    - The `DM` object
7056 . name  - The label name
7057 - value - The label value for this point
7058 
7059   Output Parameter:
7060 
7061   Level: beginner
7062 
7063 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7064 @*/
7065 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7066 {
7067   DMLabel label;
7068 
7069   PetscFunctionBegin;
7070   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7071   PetscAssertPointer(name, 2);
7072   PetscCall(DMGetLabel(dm, name, &label));
7073   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7074   PetscCall(DMLabelClearStratum(label, value));
7075   PetscFunctionReturn(PETSC_SUCCESS);
7076 }
7077 
7078 /*@
7079   DMGetNumLabels - Return the number of labels defined by on the `DM`
7080 
7081   Not Collective
7082 
7083   Input Parameter:
7084 . dm - The `DM` object
7085 
7086   Output Parameter:
7087 . numLabels - the number of Labels
7088 
7089   Level: intermediate
7090 
7091 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7092 @*/
7093 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7094 {
7095   DMLabelLink next = dm->labels;
7096   PetscInt    n    = 0;
7097 
7098   PetscFunctionBegin;
7099   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7100   PetscAssertPointer(numLabels, 2);
7101   while (next) {
7102     ++n;
7103     next = next->next;
7104   }
7105   *numLabels = n;
7106   PetscFunctionReturn(PETSC_SUCCESS);
7107 }
7108 
7109 /*@
7110   DMGetLabelName - Return the name of nth label
7111 
7112   Not Collective
7113 
7114   Input Parameters:
7115 + dm - The `DM` object
7116 - n  - the label number
7117 
7118   Output Parameter:
7119 . name - the label name
7120 
7121   Level: intermediate
7122 
7123   Developer Note:
7124   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
7125 
7126 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7127 @*/
7128 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[])
7129 {
7130   DMLabelLink next = dm->labels;
7131   PetscInt    l    = 0;
7132 
7133   PetscFunctionBegin;
7134   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7135   PetscAssertPointer(name, 3);
7136   while (next) {
7137     if (l == n) {
7138       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
7139       PetscFunctionReturn(PETSC_SUCCESS);
7140     }
7141     ++l;
7142     next = next->next;
7143   }
7144   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7145 }
7146 
7147 /*@
7148   DMHasLabel - Determine whether the `DM` has a label of a given name
7149 
7150   Not Collective
7151 
7152   Input Parameters:
7153 + dm   - The `DM` object
7154 - name - The label name
7155 
7156   Output Parameter:
7157 . hasLabel - `PETSC_TRUE` if the label is present
7158 
7159   Level: intermediate
7160 
7161 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7162 @*/
7163 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7164 {
7165   DMLabelLink next = dm->labels;
7166   const char *lname;
7167 
7168   PetscFunctionBegin;
7169   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7170   PetscAssertPointer(name, 2);
7171   PetscAssertPointer(hasLabel, 3);
7172   *hasLabel = PETSC_FALSE;
7173   while (next) {
7174     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7175     PetscCall(PetscStrcmp(name, lname, hasLabel));
7176     if (*hasLabel) break;
7177     next = next->next;
7178   }
7179   PetscFunctionReturn(PETSC_SUCCESS);
7180 }
7181 
7182 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7183 /*@
7184   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
7185 
7186   Not Collective
7187 
7188   Input Parameters:
7189 + dm   - The `DM` object
7190 - name - The label name
7191 
7192   Output Parameter:
7193 . label - The `DMLabel`, or `NULL` if the label is absent
7194 
7195   Default labels in a `DMPLEX`:
7196 + "depth"       - Holds the depth (co-dimension) of each mesh point
7197 . "celltype"    - Holds the topological type of each cell
7198 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7199 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7200 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7201 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7202 
7203   Level: intermediate
7204 
7205 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7206 @*/
7207 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7208 {
7209   DMLabelLink next = dm->labels;
7210   PetscBool   hasLabel;
7211   const char *lname;
7212 
7213   PetscFunctionBegin;
7214   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7215   PetscAssertPointer(name, 2);
7216   PetscAssertPointer(label, 3);
7217   *label = NULL;
7218   while (next) {
7219     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7220     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7221     if (hasLabel) {
7222       *label = next->label;
7223       break;
7224     }
7225     next = next->next;
7226   }
7227   PetscFunctionReturn(PETSC_SUCCESS);
7228 }
7229 
7230 /*@
7231   DMGetLabelByNum - Return the nth label on a `DM`
7232 
7233   Not Collective
7234 
7235   Input Parameters:
7236 + dm - The `DM` object
7237 - n  - the label number
7238 
7239   Output Parameter:
7240 . label - the label
7241 
7242   Level: intermediate
7243 
7244 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7245 @*/
7246 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7247 {
7248   DMLabelLink next = dm->labels;
7249   PetscInt    l    = 0;
7250 
7251   PetscFunctionBegin;
7252   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7253   PetscAssertPointer(label, 3);
7254   while (next) {
7255     if (l == n) {
7256       *label = next->label;
7257       PetscFunctionReturn(PETSC_SUCCESS);
7258     }
7259     ++l;
7260     next = next->next;
7261   }
7262   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7263 }
7264 
7265 /*@
7266   DMAddLabel - Add the label to this `DM`
7267 
7268   Not Collective
7269 
7270   Input Parameters:
7271 + dm    - The `DM` object
7272 - label - The `DMLabel`
7273 
7274   Level: developer
7275 
7276 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7277 @*/
7278 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7279 {
7280   DMLabelLink l, *p, tmpLabel;
7281   PetscBool   hasLabel;
7282   const char *lname;
7283   PetscBool   flg;
7284 
7285   PetscFunctionBegin;
7286   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7287   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7288   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7289   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7290   PetscCall(PetscCalloc1(1, &tmpLabel));
7291   tmpLabel->label  = label;
7292   tmpLabel->output = PETSC_TRUE;
7293   for (p = &dm->labels; (l = *p); p = &l->next) { }
7294   *p = tmpLabel;
7295   PetscCall(PetscObjectReference((PetscObject)label));
7296   PetscCall(PetscStrcmp(lname, "depth", &flg));
7297   if (flg) dm->depthLabel = label;
7298   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7299   if (flg) dm->celltypeLabel = label;
7300   PetscFunctionReturn(PETSC_SUCCESS);
7301 }
7302 
7303 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7304 /*@
7305   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7306 
7307   Not Collective
7308 
7309   Input Parameters:
7310 + dm    - The `DM` object
7311 - label - The `DMLabel`, having the same name, to substitute
7312 
7313   Default labels in a `DMPLEX`:
7314 + "depth"       - Holds the depth (co-dimension) of each mesh point
7315 . "celltype"    - Holds the topological type of each cell
7316 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7317 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7318 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7319 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7320 
7321   Level: intermediate
7322 
7323 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7324 @*/
7325 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7326 {
7327   DMLabelLink next = dm->labels;
7328   PetscBool   hasLabel, flg;
7329   const char *name, *lname;
7330 
7331   PetscFunctionBegin;
7332   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7333   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7334   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7335   while (next) {
7336     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7337     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7338     if (hasLabel) {
7339       PetscCall(PetscObjectReference((PetscObject)label));
7340       PetscCall(PetscStrcmp(lname, "depth", &flg));
7341       if (flg) dm->depthLabel = label;
7342       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7343       if (flg) dm->celltypeLabel = label;
7344       PetscCall(DMLabelDestroy(&next->label));
7345       next->label = label;
7346       break;
7347     }
7348     next = next->next;
7349   }
7350   PetscFunctionReturn(PETSC_SUCCESS);
7351 }
7352 
7353 /*@
7354   DMRemoveLabel - Remove the label given by name from this `DM`
7355 
7356   Not Collective
7357 
7358   Input Parameters:
7359 + dm   - The `DM` object
7360 - name - The label name
7361 
7362   Output Parameter:
7363 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7364           caller is responsible for calling `DMLabelDestroy()`.
7365 
7366   Level: developer
7367 
7368 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7369 @*/
7370 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7371 {
7372   DMLabelLink link, *pnext;
7373   PetscBool   hasLabel;
7374   const char *lname;
7375 
7376   PetscFunctionBegin;
7377   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7378   PetscAssertPointer(name, 2);
7379   if (label) {
7380     PetscAssertPointer(label, 3);
7381     *label = NULL;
7382   }
7383   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7384     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7385     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7386     if (hasLabel) {
7387       *pnext = link->next; /* Remove from list */
7388       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7389       if (hasLabel) dm->depthLabel = NULL;
7390       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7391       if (hasLabel) dm->celltypeLabel = NULL;
7392       if (label) *label = link->label;
7393       else PetscCall(DMLabelDestroy(&link->label));
7394       PetscCall(PetscFree(link));
7395       break;
7396     }
7397   }
7398   PetscFunctionReturn(PETSC_SUCCESS);
7399 }
7400 
7401 /*@
7402   DMRemoveLabelBySelf - Remove the label from this `DM`
7403 
7404   Not Collective
7405 
7406   Input Parameters:
7407 + dm           - The `DM` object
7408 . label        - The `DMLabel` to be removed from the `DM`
7409 - failNotFound - Should it fail if the label is not found in the `DM`?
7410 
7411   Level: developer
7412 
7413   Note:
7414   Only exactly the same instance is removed if found, name match is ignored.
7415   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7416   *label nullified.
7417 
7418 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7419 @*/
7420 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7421 {
7422   DMLabelLink link, *pnext;
7423   PetscBool   hasLabel = PETSC_FALSE;
7424 
7425   PetscFunctionBegin;
7426   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7427   PetscAssertPointer(label, 2);
7428   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7429   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7430   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7431   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7432     if (*label == link->label) {
7433       hasLabel = PETSC_TRUE;
7434       *pnext   = link->next; /* Remove from list */
7435       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7436       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7437       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7438       PetscCall(DMLabelDestroy(&link->label));
7439       PetscCall(PetscFree(link));
7440       break;
7441     }
7442   }
7443   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7444   PetscFunctionReturn(PETSC_SUCCESS);
7445 }
7446 
7447 /*@
7448   DMGetLabelOutput - Get the output flag for a given label
7449 
7450   Not Collective
7451 
7452   Input Parameters:
7453 + dm   - The `DM` object
7454 - name - The label name
7455 
7456   Output Parameter:
7457 . output - The flag for output
7458 
7459   Level: developer
7460 
7461 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7462 @*/
7463 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7464 {
7465   DMLabelLink next = dm->labels;
7466   const char *lname;
7467 
7468   PetscFunctionBegin;
7469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7470   PetscAssertPointer(name, 2);
7471   PetscAssertPointer(output, 3);
7472   while (next) {
7473     PetscBool flg;
7474 
7475     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7476     PetscCall(PetscStrcmp(name, lname, &flg));
7477     if (flg) {
7478       *output = next->output;
7479       PetscFunctionReturn(PETSC_SUCCESS);
7480     }
7481     next = next->next;
7482   }
7483   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7484 }
7485 
7486 /*@
7487   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7488 
7489   Not Collective
7490 
7491   Input Parameters:
7492 + dm     - The `DM` object
7493 . name   - The label name
7494 - output - `PETSC_TRUE` to save the label to the viewer
7495 
7496   Level: developer
7497 
7498 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7499 @*/
7500 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7501 {
7502   DMLabelLink next = dm->labels;
7503   const char *lname;
7504 
7505   PetscFunctionBegin;
7506   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7507   PetscAssertPointer(name, 2);
7508   while (next) {
7509     PetscBool flg;
7510 
7511     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7512     PetscCall(PetscStrcmp(name, lname, &flg));
7513     if (flg) {
7514       next->output = output;
7515       PetscFunctionReturn(PETSC_SUCCESS);
7516     }
7517     next = next->next;
7518   }
7519   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7520 }
7521 
7522 /*@
7523   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7524 
7525   Collective
7526 
7527   Input Parameters:
7528 + dmA   - The `DM` object with initial labels
7529 . dmB   - The `DM` object to which labels are copied
7530 . mode  - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7531 . all   - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7532 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7533 
7534   Level: intermediate
7535 
7536   Note:
7537   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7538 
7539 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7540 @*/
7541 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7542 {
7543   DMLabel     label, labelNew, labelOld;
7544   const char *name;
7545   PetscBool   flg;
7546   DMLabelLink link;
7547 
7548   PetscFunctionBegin;
7549   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7550   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7551   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7552   PetscValidLogicalCollectiveBool(dmA, all, 4);
7553   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7554   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7555   for (link = dmA->labels; link; link = link->next) {
7556     label = link->label;
7557     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7558     if (!all) {
7559       PetscCall(PetscStrcmp(name, "depth", &flg));
7560       if (flg) continue;
7561       PetscCall(PetscStrcmp(name, "dim", &flg));
7562       if (flg) continue;
7563       PetscCall(PetscStrcmp(name, "celltype", &flg));
7564       if (flg) continue;
7565     }
7566     PetscCall(DMGetLabel(dmB, name, &labelOld));
7567     if (labelOld) {
7568       switch (emode) {
7569       case DM_COPY_LABELS_KEEP:
7570         continue;
7571       case DM_COPY_LABELS_REPLACE:
7572         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7573         break;
7574       case DM_COPY_LABELS_FAIL:
7575         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7576       default:
7577         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7578       }
7579     }
7580     if (mode == PETSC_COPY_VALUES) {
7581       PetscCall(DMLabelDuplicate(label, &labelNew));
7582     } else {
7583       labelNew = label;
7584     }
7585     PetscCall(DMAddLabel(dmB, labelNew));
7586     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7587   }
7588   PetscFunctionReturn(PETSC_SUCCESS);
7589 }
7590 
7591 /*@C
7592   DMCompareLabels - Compare labels between two `DM` objects
7593 
7594   Collective; No Fortran Support
7595 
7596   Input Parameters:
7597 + dm0 - First `DM` object
7598 - dm1 - Second `DM` object
7599 
7600   Output Parameters:
7601 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7602 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7603 
7604   Level: intermediate
7605 
7606   Notes:
7607   The output flag equal will be the same on all processes.
7608 
7609   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7610 
7611   Make sure to pass equal is `NULL` on all processes or none of them.
7612 
7613   The output message is set independently on each rank.
7614 
7615   message must be freed with `PetscFree()`
7616 
7617   If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner.
7618 
7619   Make sure to pass message as `NULL` on all processes or no processes.
7620 
7621   Labels are matched by name. If the number of labels and their names are equal,
7622   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7623 
7624   Developer Note:
7625   Can automatically generate the Fortran stub because `message` must be freed with `PetscFree()`
7626 
7627 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7628 @*/
7629 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7630 {
7631   PetscInt    n, i;
7632   char        msg[PETSC_MAX_PATH_LEN] = "";
7633   PetscBool   eq;
7634   MPI_Comm    comm;
7635   PetscMPIInt rank;
7636 
7637   PetscFunctionBegin;
7638   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7639   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7640   PetscCheckSameComm(dm0, 1, dm1, 2);
7641   if (equal) PetscAssertPointer(equal, 3);
7642   if (message) PetscAssertPointer(message, 4);
7643   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7644   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7645   {
7646     PetscInt n1;
7647 
7648     PetscCall(DMGetNumLabels(dm0, &n));
7649     PetscCall(DMGetNumLabels(dm1, &n1));
7650     eq = (PetscBool)(n == n1);
7651     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7652     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7653     if (!eq) goto finish;
7654   }
7655   for (i = 0; i < n; i++) {
7656     DMLabel     l0, l1;
7657     const char *name;
7658     char       *msgInner;
7659 
7660     /* Ignore label order */
7661     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7662     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7663     PetscCall(DMGetLabel(dm1, name, &l1));
7664     if (!l1) {
7665       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7666       eq = PETSC_FALSE;
7667       break;
7668     }
7669     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7670     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7671     PetscCall(PetscFree(msgInner));
7672     if (!eq) break;
7673   }
7674   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7675 finish:
7676   /* If message output arg not set, print to stderr */
7677   if (message) {
7678     *message = NULL;
7679     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7680   } else {
7681     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7682     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7683   }
7684   /* If same output arg not ser and labels are not equal, throw error */
7685   if (equal) *equal = eq;
7686   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7687   PetscFunctionReturn(PETSC_SUCCESS);
7688 }
7689 
7690 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7691 {
7692   PetscFunctionBegin;
7693   PetscAssertPointer(label, 2);
7694   if (!*label) {
7695     PetscCall(DMCreateLabel(dm, name));
7696     PetscCall(DMGetLabel(dm, name, label));
7697   }
7698   PetscCall(DMLabelSetValue(*label, point, value));
7699   PetscFunctionReturn(PETSC_SUCCESS);
7700 }
7701 
7702 /*
7703   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7704   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7705   (label, id) pair in the DM.
7706 
7707   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7708   each label.
7709 */
7710 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7711 {
7712   DMUniversalLabel ul;
7713   PetscBool       *active;
7714   PetscInt         pStart, pEnd, p, Nl, l, m;
7715 
7716   PetscFunctionBegin;
7717   PetscCall(PetscMalloc1(1, &ul));
7718   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7719   PetscCall(DMGetNumLabels(dm, &Nl));
7720   PetscCall(PetscCalloc1(Nl, &active));
7721   ul->Nl = 0;
7722   for (l = 0; l < Nl; ++l) {
7723     PetscBool   isdepth, iscelltype;
7724     const char *name;
7725 
7726     PetscCall(DMGetLabelName(dm, l, &name));
7727     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7728     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7729     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7730     if (active[l]) ++ul->Nl;
7731   }
7732   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7733   ul->Nv = 0;
7734   for (l = 0, m = 0; l < Nl; ++l) {
7735     DMLabel     label;
7736     PetscInt    nv;
7737     const char *name;
7738 
7739     if (!active[l]) continue;
7740     PetscCall(DMGetLabelName(dm, l, &name));
7741     PetscCall(DMGetLabelByNum(dm, l, &label));
7742     PetscCall(DMLabelGetNumValues(label, &nv));
7743     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7744     ul->indices[m] = l;
7745     ul->Nv += nv;
7746     ul->offsets[m + 1] = nv;
7747     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7748     ++m;
7749   }
7750   for (l = 1; l <= ul->Nl; ++l) {
7751     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7752     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7753   }
7754   for (l = 0; l < ul->Nl; ++l) {
7755     PetscInt b;
7756 
7757     ul->masks[l] = 0;
7758     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7759   }
7760   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7761   for (l = 0, m = 0; l < Nl; ++l) {
7762     DMLabel         label;
7763     IS              valueIS;
7764     const PetscInt *varr;
7765     PetscInt        nv, v;
7766 
7767     if (!active[l]) continue;
7768     PetscCall(DMGetLabelByNum(dm, l, &label));
7769     PetscCall(DMLabelGetNumValues(label, &nv));
7770     PetscCall(DMLabelGetValueIS(label, &valueIS));
7771     PetscCall(ISGetIndices(valueIS, &varr));
7772     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7773     PetscCall(ISRestoreIndices(valueIS, &varr));
7774     PetscCall(ISDestroy(&valueIS));
7775     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7776     ++m;
7777   }
7778   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7779   for (p = pStart; p < pEnd; ++p) {
7780     PetscInt  uval   = 0;
7781     PetscBool marked = PETSC_FALSE;
7782 
7783     for (l = 0, m = 0; l < Nl; ++l) {
7784       DMLabel  label;
7785       PetscInt val, defval, loc, nv;
7786 
7787       if (!active[l]) continue;
7788       PetscCall(DMGetLabelByNum(dm, l, &label));
7789       PetscCall(DMLabelGetValue(label, p, &val));
7790       PetscCall(DMLabelGetDefaultValue(label, &defval));
7791       if (val == defval) {
7792         ++m;
7793         continue;
7794       }
7795       nv     = ul->offsets[m + 1] - ul->offsets[m];
7796       marked = PETSC_TRUE;
7797       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7798       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7799       uval += (loc + 1) << ul->bits[m];
7800       ++m;
7801     }
7802     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7803   }
7804   PetscCall(PetscFree(active));
7805   *universal = ul;
7806   PetscFunctionReturn(PETSC_SUCCESS);
7807 }
7808 
7809 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7810 {
7811   PetscInt l;
7812 
7813   PetscFunctionBegin;
7814   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7815   PetscCall(DMLabelDestroy(&(*universal)->label));
7816   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7817   PetscCall(PetscFree((*universal)->values));
7818   PetscCall(PetscFree(*universal));
7819   *universal = NULL;
7820   PetscFunctionReturn(PETSC_SUCCESS);
7821 }
7822 
7823 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7824 {
7825   PetscFunctionBegin;
7826   PetscAssertPointer(ulabel, 2);
7827   *ulabel = ul->label;
7828   PetscFunctionReturn(PETSC_SUCCESS);
7829 }
7830 
7831 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7832 {
7833   PetscInt Nl = ul->Nl, l;
7834 
7835   PetscFunctionBegin;
7836   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7837   for (l = 0; l < Nl; ++l) {
7838     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7839     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7840   }
7841   if (preserveOrder) {
7842     for (l = 0; l < ul->Nl; ++l) {
7843       const char *name;
7844       PetscBool   match;
7845 
7846       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7847       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7848       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]);
7849     }
7850   }
7851   PetscFunctionReturn(PETSC_SUCCESS);
7852 }
7853 
7854 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7855 {
7856   PetscInt l;
7857 
7858   PetscFunctionBegin;
7859   for (l = 0; l < ul->Nl; ++l) {
7860     DMLabel  label;
7861     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7862 
7863     if (lval) {
7864       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7865       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7866       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7867     }
7868   }
7869   PetscFunctionReturn(PETSC_SUCCESS);
7870 }
7871 
7872 /*@
7873   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7874 
7875   Not Collective
7876 
7877   Input Parameter:
7878 . dm - The `DM` object
7879 
7880   Output Parameter:
7881 . cdm - The coarse `DM`
7882 
7883   Level: intermediate
7884 
7885 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7886 @*/
7887 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7888 {
7889   PetscFunctionBegin;
7890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7891   PetscAssertPointer(cdm, 2);
7892   *cdm = dm->coarseMesh;
7893   PetscFunctionReturn(PETSC_SUCCESS);
7894 }
7895 
7896 /*@
7897   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7898 
7899   Input Parameters:
7900 + dm  - The `DM` object
7901 - cdm - The coarse `DM`
7902 
7903   Level: intermediate
7904 
7905   Note:
7906   Normally this is set automatically by `DMRefine()`
7907 
7908 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7909 @*/
7910 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7911 {
7912   PetscFunctionBegin;
7913   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7914   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7915   if (dm == cdm) cdm = NULL;
7916   PetscCall(PetscObjectReference((PetscObject)cdm));
7917   PetscCall(DMDestroy(&dm->coarseMesh));
7918   dm->coarseMesh = cdm;
7919   PetscFunctionReturn(PETSC_SUCCESS);
7920 }
7921 
7922 /*@
7923   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7924 
7925   Input Parameter:
7926 . dm - The `DM` object
7927 
7928   Output Parameter:
7929 . fdm - The fine `DM`
7930 
7931   Level: intermediate
7932 
7933 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7934 @*/
7935 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7936 {
7937   PetscFunctionBegin;
7938   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7939   PetscAssertPointer(fdm, 2);
7940   *fdm = dm->fineMesh;
7941   PetscFunctionReturn(PETSC_SUCCESS);
7942 }
7943 
7944 /*@
7945   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7946 
7947   Input Parameters:
7948 + dm  - The `DM` object
7949 - fdm - The fine `DM`
7950 
7951   Level: developer
7952 
7953   Note:
7954   Normally this is set automatically by `DMCoarsen()`
7955 
7956 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7957 @*/
7958 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7959 {
7960   PetscFunctionBegin;
7961   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7962   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7963   if (dm == fdm) fdm = NULL;
7964   PetscCall(PetscObjectReference((PetscObject)fdm));
7965   PetscCall(DMDestroy(&dm->fineMesh));
7966   dm->fineMesh = fdm;
7967   PetscFunctionReturn(PETSC_SUCCESS);
7968 }
7969 
7970 /*@C
7971   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7972 
7973   Collective
7974 
7975   Input Parameters:
7976 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7977 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7978 . name     - The BC name
7979 . label    - The label defining constrained points
7980 . Nv       - The number of `DMLabel` values for constrained points
7981 . values   - An array of values for constrained points
7982 . field    - The field to constrain
7983 . Nc       - The number of constrained field components (0 will constrain all fields)
7984 . comps    - An array of constrained component numbers
7985 . bcFunc   - A pointwise function giving boundary values
7986 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7987 - ctx      - An optional user context for bcFunc
7988 
7989   Output Parameter:
7990 . bd - (Optional) Boundary number
7991 
7992   Options Database Keys:
7993 + -bc_<boundary name> <num>      - Overrides the boundary ids
7994 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7995 
7996   Level: intermediate
7997 
7998   Notes:
7999   Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
8000 .vb
8001  void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8002 .ve
8003 
8004   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
8005 
8006 .vb
8007   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8008               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8009               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8010               PetscReal time, const PetscReal x[], PetscScalar bcval[])
8011 .ve
8012 + dim - the spatial dimension
8013 . Nf - the number of fields
8014 . uOff - the offset into u[] and u_t[] for each field
8015 . uOff_x - the offset into u_x[] for each field
8016 . u - each field evaluated at the current point
8017 . u_t - the time derivative of each field evaluated at the current point
8018 . u_x - the gradient of each field evaluated at the current point
8019 . aOff - the offset into a[] and a_t[] for each auxiliary field
8020 . aOff_x - the offset into a_x[] for each auxiliary field
8021 . a - each auxiliary field evaluated at the current point
8022 . a_t - the time derivative of each auxiliary field evaluated at the current point
8023 . a_x - the gradient of auxiliary each field evaluated at the current point
8024 . t - current time
8025 . x - coordinates of the current point
8026 . numConstants - number of constant parameters
8027 . constants - constant parameters
8028 - bcval - output values at the current point
8029 
8030 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
8031 @*/
8032 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)
8033 {
8034   PetscDS ds;
8035 
8036   PetscFunctionBegin;
8037   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8038   PetscValidLogicalCollectiveEnum(dm, type, 2);
8039   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8040   PetscValidLogicalCollectiveInt(dm, Nv, 5);
8041   PetscValidLogicalCollectiveInt(dm, field, 7);
8042   PetscValidLogicalCollectiveInt(dm, Nc, 8);
8043   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
8044   PetscCall(DMGetDS(dm, &ds));
8045   /* Complete label */
8046   if (label) {
8047     PetscObject  obj;
8048     PetscClassId id;
8049 
8050     PetscCall(DMGetField(dm, field, NULL, &obj));
8051     PetscCall(PetscObjectGetClassId(obj, &id));
8052     if (id == PETSCFE_CLASSID) {
8053       DM plex;
8054 
8055       PetscCall(DMConvert(dm, DMPLEX, &plex));
8056       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8057       PetscCall(DMDestroy(&plex));
8058     }
8059   }
8060   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8061   PetscFunctionReturn(PETSC_SUCCESS);
8062 }
8063 
8064 /* TODO Remove this since now the structures are the same */
8065 static PetscErrorCode DMPopulateBoundary(DM dm)
8066 {
8067   PetscDS     ds;
8068   DMBoundary *lastnext;
8069   DSBoundary  dsbound;
8070 
8071   PetscFunctionBegin;
8072   PetscCall(DMGetDS(dm, &ds));
8073   dsbound = ds->boundary;
8074   if (dm->boundary) {
8075     DMBoundary next = dm->boundary;
8076 
8077     /* quick check to see if the PetscDS has changed */
8078     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
8079     /* the PetscDS has changed: tear down and rebuild */
8080     while (next) {
8081       DMBoundary b = next;
8082 
8083       next = b->next;
8084       PetscCall(PetscFree(b));
8085     }
8086     dm->boundary = NULL;
8087   }
8088 
8089   lastnext = &dm->boundary;
8090   while (dsbound) {
8091     DMBoundary dmbound;
8092 
8093     PetscCall(PetscNew(&dmbound));
8094     dmbound->dsboundary = dsbound;
8095     dmbound->label      = dsbound->label;
8096     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8097     *lastnext = dmbound;
8098     lastnext  = &dmbound->next;
8099     dsbound   = dsbound->next;
8100   }
8101   PetscFunctionReturn(PETSC_SUCCESS);
8102 }
8103 
8104 /* TODO: missing manual page */
8105 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8106 {
8107   DMBoundary b;
8108 
8109   PetscFunctionBegin;
8110   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8111   PetscAssertPointer(isBd, 3);
8112   *isBd = PETSC_FALSE;
8113   PetscCall(DMPopulateBoundary(dm));
8114   b = dm->boundary;
8115   while (b && !*isBd) {
8116     DMLabel    label = b->label;
8117     DSBoundary dsb   = b->dsboundary;
8118     PetscInt   i;
8119 
8120     if (label) {
8121       for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8122     }
8123     b = b->next;
8124   }
8125   PetscFunctionReturn(PETSC_SUCCESS);
8126 }
8127 
8128 /*@C
8129   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
8130 
8131   Collective
8132 
8133   Input Parameters:
8134 + dm    - The `DM`
8135 . time  - The time
8136 . funcs - The coordinate functions to evaluate, one per field
8137 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8138 - mode  - The insertion mode for values
8139 
8140   Output Parameter:
8141 . X - vector
8142 
8143   Calling sequence of `funcs`:
8144 + dim  - The spatial dimension
8145 . time - The time at which to sample
8146 . x    - The coordinates
8147 . Nc   - The number of components
8148 . u    - The output field values
8149 - ctx  - optional user-defined function context
8150 
8151   Level: developer
8152 
8153   Developer Notes:
8154   This API is specific to only particular usage of `DM`
8155 
8156   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8157 
8158 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8159 @*/
8160 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)
8161 {
8162   Vec localX;
8163 
8164   PetscFunctionBegin;
8165   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8166   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
8167   PetscCall(DMGetLocalVector(dm, &localX));
8168   PetscCall(VecSet(localX, 0.));
8169   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8170   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8171   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8172   PetscCall(DMRestoreLocalVector(dm, &localX));
8173   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
8174   PetscFunctionReturn(PETSC_SUCCESS);
8175 }
8176 
8177 /*@C
8178   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
8179 
8180   Not Collective
8181 
8182   Input Parameters:
8183 + dm    - The `DM`
8184 . time  - The time
8185 . funcs - The coordinate functions to evaluate, one per field
8186 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8187 - mode  - The insertion mode for values
8188 
8189   Output Parameter:
8190 . localX - vector
8191 
8192   Calling sequence of `funcs`:
8193 + dim  - The spatial dimension
8194 . time - The current timestep
8195 . x    - The coordinates
8196 . Nc   - The number of components
8197 . u    - The output field values
8198 - ctx  - optional user-defined function context
8199 
8200   Level: developer
8201 
8202   Developer Notes:
8203   This API is specific to only particular usage of `DM`
8204 
8205   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8206 
8207 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8208 @*/
8209 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)
8210 {
8211   PetscFunctionBegin;
8212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8213   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8214   PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX);
8215   PetscFunctionReturn(PETSC_SUCCESS);
8216 }
8217 
8218 /*@C
8219   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.
8220 
8221   Collective
8222 
8223   Input Parameters:
8224 + dm     - The `DM`
8225 . time   - The time
8226 . numIds - The number of ids
8227 . ids    - The ids
8228 . Nc     - The number of components
8229 . comps  - The components
8230 . label  - The `DMLabel` selecting the portion of the mesh for projection
8231 . funcs  - The coordinate functions to evaluate, one per field
8232 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8233 - mode   - The insertion mode for values
8234 
8235   Output Parameter:
8236 . X - vector
8237 
8238   Calling sequence of `funcs`:
8239 + dim  - The spatial dimension
8240 . time - The current timestep
8241 . x    - The coordinates
8242 . Nc   - The number of components
8243 . u    - The output field values
8244 - ctx  - optional user-defined function context
8245 
8246   Level: developer
8247 
8248   Developer Notes:
8249   This API is specific to only particular usage of `DM`
8250 
8251   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8252 
8253 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8254 @*/
8255 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)
8256 {
8257   Vec localX;
8258 
8259   PetscFunctionBegin;
8260   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8261   PetscCall(DMGetLocalVector(dm, &localX));
8262   PetscCall(VecSet(localX, 0.));
8263   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8264   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8265   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8266   PetscCall(DMRestoreLocalVector(dm, &localX));
8267   PetscFunctionReturn(PETSC_SUCCESS);
8268 }
8269 
8270 /*@C
8271   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.
8272 
8273   Not Collective
8274 
8275   Input Parameters:
8276 + dm     - The `DM`
8277 . time   - The time
8278 . label  - The `DMLabel` selecting the portion of the mesh for projection
8279 . numIds - The number of ids
8280 . ids    - The ids
8281 . Nc     - The number of components
8282 . comps  - The components
8283 . funcs  - The coordinate functions to evaluate, one per field
8284 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8285 - mode   - The insertion mode for values
8286 
8287   Output Parameter:
8288 . localX - vector
8289 
8290   Calling sequence of `funcs`:
8291 + dim  - The spatial dimension
8292 . time - The current time
8293 . x    - The coordinates
8294 . Nc   - The number of components
8295 . u    - The output field values
8296 - ctx  - optional user-defined function context
8297 
8298   Level: developer
8299 
8300   Developer Notes:
8301   This API is specific to only particular usage of `DM`
8302 
8303   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8304 
8305 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8306 @*/
8307 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)
8308 {
8309   PetscFunctionBegin;
8310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8311   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8312   PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8313   PetscFunctionReturn(PETSC_SUCCESS);
8314 }
8315 
8316 /*@C
8317   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.
8318 
8319   Not Collective
8320 
8321   Input Parameters:
8322 + dm     - The `DM`
8323 . time   - The time
8324 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8325 . funcs  - The functions to evaluate, one per field
8326 - mode   - The insertion mode for values
8327 
8328   Output Parameter:
8329 . localX - The output vector
8330 
8331   Calling sequence of `funcs`:
8332 + dim          - The spatial dimension
8333 . Nf           - The number of input fields
8334 . NfAux        - The number of input auxiliary fields
8335 . uOff         - The offset of each field in u[]
8336 . uOff_x       - The offset of each field in u_x[]
8337 . u            - The field values at this point in space
8338 . u_t          - The field time derivative at this point in space (or NULL)
8339 . u_x          - The field derivatives at this point in space
8340 . aOff         - The offset of each auxiliary field in u[]
8341 . aOff_x       - The offset of each auxiliary field in u_x[]
8342 . a            - The auxiliary field values at this point in space
8343 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8344 . a_x          - The auxiliary field derivatives at this point in space
8345 . t            - The current time
8346 . x            - The coordinates of this point
8347 . numConstants - The number of constants
8348 . constants    - The value of each constant
8349 - f            - The value of the function at this point in space
8350 
8351   Level: intermediate
8352 
8353   Note:
8354   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.
8355   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
8356   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8357   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8358 
8359   Developer Notes:
8360   This API is specific to only particular usage of `DM`
8361 
8362   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8363 
8364 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8365 `DMProjectFunction()`, `DMComputeL2Diff()`
8366 @*/
8367 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)
8368 {
8369   PetscFunctionBegin;
8370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8371   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8372   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8373   PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX);
8374   PetscFunctionReturn(PETSC_SUCCESS);
8375 }
8376 
8377 /*@C
8378   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.
8379 
8380   Not Collective
8381 
8382   Input Parameters:
8383 + dm     - The `DM`
8384 . time   - The time
8385 . label  - The `DMLabel` marking the portion of the domain to output
8386 . numIds - The number of label ids to use
8387 . ids    - The label ids to use for marking
8388 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8389 . comps  - The components to set in the output, or `NULL` for all components
8390 . localU - The input field vector
8391 . funcs  - The functions to evaluate, one per field
8392 - mode   - The insertion mode for values
8393 
8394   Output Parameter:
8395 . localX - The output vector
8396 
8397   Calling sequence of `funcs`:
8398 + dim          - The spatial dimension
8399 . Nf           - The number of input fields
8400 . NfAux        - The number of input auxiliary fields
8401 . uOff         - The offset of each field in u[]
8402 . uOff_x       - The offset of each field in u_x[]
8403 . u            - The field values at this point in space
8404 . u_t          - The field time derivative at this point in space (or NULL)
8405 . u_x          - The field derivatives at this point in space
8406 . aOff         - The offset of each auxiliary field in u[]
8407 . aOff_x       - The offset of each auxiliary field in u_x[]
8408 . a            - The auxiliary field values at this point in space
8409 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8410 . a_x          - The auxiliary field derivatives at this point in space
8411 . t            - The current time
8412 . x            - The coordinates of this point
8413 . numConstants - The number of constants
8414 . constants    - The value of each constant
8415 - f            - The value of the function at this point in space
8416 
8417   Level: intermediate
8418 
8419   Note:
8420   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.
8421   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
8422   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8423   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8424 
8425   Developer Notes:
8426   This API is specific to only particular usage of `DM`
8427 
8428   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8429 
8430 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8431 @*/
8432 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)
8433 {
8434   PetscFunctionBegin;
8435   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8436   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8437   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8438   PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8439   PetscFunctionReturn(PETSC_SUCCESS);
8440 }
8441 
8442 /*@C
8443   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.
8444 
8445   Not Collective
8446 
8447   Input Parameters:
8448 + dm     - The `DM`
8449 . time   - The time
8450 . label  - The `DMLabel` marking the portion of the domain to output
8451 . numIds - The number of label ids to use
8452 . ids    - The label ids to use for marking
8453 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8454 . comps  - The components to set in the output, or `NULL` for all components
8455 . U      - The input field vector
8456 . funcs  - The functions to evaluate, one per field
8457 - mode   - The insertion mode for values
8458 
8459   Output Parameter:
8460 . X - The output vector
8461 
8462   Calling sequence of `funcs`:
8463 + dim          - The spatial dimension
8464 . Nf           - The number of input fields
8465 . NfAux        - The number of input auxiliary fields
8466 . uOff         - The offset of each field in u[]
8467 . uOff_x       - The offset of each field in u_x[]
8468 . u            - The field values at this point in space
8469 . u_t          - The field time derivative at this point in space (or NULL)
8470 . u_x          - The field derivatives at this point in space
8471 . aOff         - The offset of each auxiliary field in u[]
8472 . aOff_x       - The offset of each auxiliary field in u_x[]
8473 . a            - The auxiliary field values at this point in space
8474 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8475 . a_x          - The auxiliary field derivatives at this point in space
8476 . t            - The current time
8477 . x            - The coordinates of this point
8478 . numConstants - The number of constants
8479 . constants    - The value of each constant
8480 - f            - The value of the function at this point in space
8481 
8482   Level: intermediate
8483 
8484   Note:
8485   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.
8486   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
8487   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8488   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8489 
8490   Developer Notes:
8491   This API is specific to only particular usage of `DM`
8492 
8493   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8494 
8495 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8496 @*/
8497 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)
8498 {
8499   DM  dmIn;
8500   Vec localU, localX;
8501 
8502   PetscFunctionBegin;
8503   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8504   PetscCall(VecGetDM(U, &dmIn));
8505   PetscCall(DMGetLocalVector(dmIn, &localU));
8506   PetscCall(DMGetLocalVector(dm, &localX));
8507   PetscCall(VecSet(localX, 0.));
8508   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8509   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8510   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8511   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8512   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8513   PetscCall(DMRestoreLocalVector(dm, &localX));
8514   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8515   PetscFunctionReturn(PETSC_SUCCESS);
8516 }
8517 
8518 /*@C
8519   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.
8520 
8521   Not Collective
8522 
8523   Input Parameters:
8524 + dm     - The `DM`
8525 . time   - The time
8526 . label  - The `DMLabel` marking the portion of the domain boundary to output
8527 . numIds - The number of label ids to use
8528 . ids    - The label ids to use for marking
8529 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8530 . comps  - The components to set in the output, or `NULL` for all components
8531 . localU - The input field vector
8532 . funcs  - The functions to evaluate, one per field
8533 - mode   - The insertion mode for values
8534 
8535   Output Parameter:
8536 . localX - The output vector
8537 
8538   Calling sequence of `funcs`:
8539 + dim          - The spatial dimension
8540 . Nf           - The number of input fields
8541 . NfAux        - The number of input auxiliary fields
8542 . uOff         - The offset of each field in u[]
8543 . uOff_x       - The offset of each field in u_x[]
8544 . u            - The field values at this point in space
8545 . u_t          - The field time derivative at this point in space (or NULL)
8546 . u_x          - The field derivatives at this point in space
8547 . aOff         - The offset of each auxiliary field in u[]
8548 . aOff_x       - The offset of each auxiliary field in u_x[]
8549 . a            - The auxiliary field values at this point in space
8550 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8551 . a_x          - The auxiliary field derivatives at this point in space
8552 . t            - The current time
8553 . x            - The coordinates of this point
8554 . n            - The face normal
8555 . numConstants - The number of constants
8556 . constants    - The value of each constant
8557 - f            - The value of the function at this point in space
8558 
8559   Level: intermediate
8560 
8561   Note:
8562   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.
8563   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
8564   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8565   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8566 
8567   Developer Notes:
8568   This API is specific to only particular usage of `DM`
8569 
8570   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8571 
8572 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8573 @*/
8574 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)
8575 {
8576   PetscFunctionBegin;
8577   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8578   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8579   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8580   PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8581   PetscFunctionReturn(PETSC_SUCCESS);
8582 }
8583 
8584 /*@C
8585   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8586 
8587   Collective
8588 
8589   Input Parameters:
8590 + dm    - The `DM`
8591 . time  - The time
8592 . funcs - The functions to evaluate for each field component
8593 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8594 - X     - The coefficient vector u_h, a global vector
8595 
8596   Output Parameter:
8597 . diff - The diff ||u - u_h||_2
8598 
8599   Level: developer
8600 
8601   Developer Notes:
8602   This API is specific to only particular usage of `DM`
8603 
8604   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8605 
8606 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8607 @*/
8608 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8609 {
8610   PetscFunctionBegin;
8611   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8612   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8613   PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff);
8614   PetscFunctionReturn(PETSC_SUCCESS);
8615 }
8616 
8617 /*@C
8618   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8619 
8620   Collective
8621 
8622   Input Parameters:
8623 + dm    - The `DM`
8624 . time  - The time
8625 . funcs - The gradient functions to evaluate for each field component
8626 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8627 . X     - The coefficient vector u_h, a global vector
8628 - n     - The vector to project along
8629 
8630   Output Parameter:
8631 . diff - The diff ||(grad u - grad u_h) . n||_2
8632 
8633   Level: developer
8634 
8635   Developer Notes:
8636   This API is specific to only particular usage of `DM`
8637 
8638   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8639 
8640 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8641 @*/
8642 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)
8643 {
8644   PetscFunctionBegin;
8645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8646   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8647   PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff);
8648   PetscFunctionReturn(PETSC_SUCCESS);
8649 }
8650 
8651 /*@C
8652   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8653 
8654   Collective
8655 
8656   Input Parameters:
8657 + dm    - The `DM`
8658 . time  - The time
8659 . funcs - The functions to evaluate for each field component
8660 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8661 - X     - The coefficient vector u_h, a global vector
8662 
8663   Output Parameter:
8664 . diff - The array of differences, ||u^f - u^f_h||_2
8665 
8666   Level: developer
8667 
8668   Developer Notes:
8669   This API is specific to only particular usage of `DM`
8670 
8671   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8672 
8673 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8674 @*/
8675 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8676 {
8677   PetscFunctionBegin;
8678   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8679   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8680   PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff);
8681   PetscFunctionReturn(PETSC_SUCCESS);
8682 }
8683 
8684 /*@C
8685   DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8686 
8687   Not Collective
8688 
8689   Input Parameter:
8690 . dm - The `DM`
8691 
8692   Output Parameters:
8693 + nranks - the number of neighbours
8694 - ranks  - the neighbors ranks
8695 
8696   Level: beginner
8697 
8698   Note:
8699   Do not free the array, it is freed when the `DM` is destroyed.
8700 
8701 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8702 @*/
8703 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8704 {
8705   PetscFunctionBegin;
8706   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8707   PetscUseTypeMethod(dm, getneighbors, nranks, ranks);
8708   PetscFunctionReturn(PETSC_SUCCESS);
8709 }
8710 
8711 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8712 
8713 /*
8714     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8715     This must be a different function because it requires DM which is not defined in the Mat library
8716 */
8717 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8718 {
8719   PetscFunctionBegin;
8720   if (coloring->ctype == IS_COLORING_LOCAL) {
8721     Vec x1local;
8722     DM  dm;
8723     PetscCall(MatGetDM(J, &dm));
8724     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8725     PetscCall(DMGetLocalVector(dm, &x1local));
8726     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8727     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8728     x1 = x1local;
8729   }
8730   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8731   if (coloring->ctype == IS_COLORING_LOCAL) {
8732     DM dm;
8733     PetscCall(MatGetDM(J, &dm));
8734     PetscCall(DMRestoreLocalVector(dm, &x1));
8735   }
8736   PetscFunctionReturn(PETSC_SUCCESS);
8737 }
8738 
8739 /*@
8740   MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8741 
8742   Input Parameters:
8743 + coloring   - The matrix to get the `DM` from
8744 - fdcoloring - the `MatFDColoring` object
8745 
8746   Level: advanced
8747 
8748   Developer Note:
8749   This routine exists because the PETSc `Mat` library does not know about the `DM` objects
8750 
8751 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8752 @*/
8753 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8754 {
8755   PetscFunctionBegin;
8756   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8757   PetscFunctionReturn(PETSC_SUCCESS);
8758 }
8759 
8760 /*@
8761   DMGetCompatibility - determine if two `DM`s are compatible
8762 
8763   Collective
8764 
8765   Input Parameters:
8766 + dm1 - the first `DM`
8767 - dm2 - the second `DM`
8768 
8769   Output Parameters:
8770 + compatible - whether or not the two `DM`s are compatible
8771 - set        - whether or not the compatible value was actually determined and set
8772 
8773   Level: advanced
8774 
8775   Notes:
8776   Two `DM`s are deemed compatible if they represent the same parallel decomposition
8777   of the same topology. This implies that the section (field data) on one
8778   "makes sense" with respect to the topology and parallel decomposition of the other.
8779   Loosely speaking, compatible `DM`s represent the same domain and parallel
8780   decomposition, but hold different data.
8781 
8782   Typically, one would confirm compatibility if intending to simultaneously iterate
8783   over a pair of vectors obtained from different `DM`s.
8784 
8785   For example, two `DMDA` objects are compatible if they have the same local
8786   and global sizes and the same stencil width. They can have different numbers
8787   of degrees of freedom per node. Thus, one could use the node numbering from
8788   either `DM` in bounds for a loop over vectors derived from either `DM`.
8789 
8790   Consider the operation of summing data living on a 2-dof `DMDA` to data living
8791   on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8792 .vb
8793   ...
8794   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8795   if (set && compatible)  {
8796     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8797     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8798     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8799     for (j=y; j<y+n; ++j) {
8800       for (i=x; i<x+m, ++i) {
8801         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8802       }
8803     }
8804     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8805     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8806   } else {
8807     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8808   }
8809   ...
8810 .ve
8811 
8812   Checking compatibility might be expensive for a given implementation of `DM`,
8813   or might be impossible to unambiguously confirm or deny. For this reason,
8814   this function may decline to determine compatibility, and hence users should
8815   always check the "set" output parameter.
8816 
8817   A `DM` is always compatible with itself.
8818 
8819   In the current implementation, `DM`s which live on "unequal" communicators
8820   (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8821   incompatible.
8822 
8823   This function is labeled "Collective," as information about all subdomains
8824   is required on each rank. However, in `DM` implementations which store all this
8825   information locally, this function may be merely "Logically Collective".
8826 
8827   Developer Note:
8828   Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8829   iff B is compatible with A. Thus, this function checks the implementations
8830   of both dm and dmc (if they are of different types), attempting to determine
8831   compatibility. It is left to `DM` implementers to ensure that symmetry is
8832   preserved. The simplest way to do this is, when implementing type-specific
8833   logic for this function, is to check for existing logic in the implementation
8834   of other `DM` types and let *set = PETSC_FALSE if found.
8835 
8836 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8837 @*/
8838 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8839 {
8840   PetscMPIInt compareResult;
8841   DMType      type, type2;
8842   PetscBool   sameType;
8843 
8844   PetscFunctionBegin;
8845   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8846   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8847 
8848   /* Declare a DM compatible with itself */
8849   if (dm1 == dm2) {
8850     *set        = PETSC_TRUE;
8851     *compatible = PETSC_TRUE;
8852     PetscFunctionReturn(PETSC_SUCCESS);
8853   }
8854 
8855   /* Declare a DM incompatible with a DM that lives on an "unequal"
8856      communicator. Note that this does not preclude compatibility with
8857      DMs living on "congruent" or "similar" communicators, but this must be
8858      determined by the implementation-specific logic */
8859   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8860   if (compareResult == MPI_UNEQUAL) {
8861     *set        = PETSC_TRUE;
8862     *compatible = PETSC_FALSE;
8863     PetscFunctionReturn(PETSC_SUCCESS);
8864   }
8865 
8866   /* Pass to the implementation-specific routine, if one exists. */
8867   if (dm1->ops->getcompatibility) {
8868     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8869     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8870   }
8871 
8872   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8873      with an implementation of this function from dm2 */
8874   PetscCall(DMGetType(dm1, &type));
8875   PetscCall(DMGetType(dm2, &type2));
8876   PetscCall(PetscStrcmp(type, type2, &sameType));
8877   if (!sameType && dm2->ops->getcompatibility) {
8878     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8879   } else {
8880     *set = PETSC_FALSE;
8881   }
8882   PetscFunctionReturn(PETSC_SUCCESS);
8883 }
8884 
8885 /*@C
8886   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8887 
8888   Logically Collective
8889 
8890   Input Parameters:
8891 + dm             - the `DM`
8892 . f              - the monitor function
8893 . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8894 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence
8895 
8896   Options Database Key:
8897 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8898                        does not cancel those set via the options database.
8899 
8900   Level: intermediate
8901 
8902   Note:
8903   Several different monitoring routines may be set by calling
8904   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8905   order in which they were set.
8906 
8907   Fortran Note:
8908   Only a single monitor function can be set for each `DM` object
8909 
8910   Developer Note:
8911   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8912 
8913 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`, `PetscCtxDestroyFn`
8914 @*/
8915 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy)
8916 {
8917   PetscInt m;
8918 
8919   PetscFunctionBegin;
8920   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8921   for (m = 0; m < dm->numbermonitors; ++m) {
8922     PetscBool identical;
8923 
8924     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))f, mctx, monitordestroy, (PetscErrorCode (*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8925     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
8926   }
8927   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8928   dm->monitor[dm->numbermonitors]          = f;
8929   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8930   dm->monitorcontext[dm->numbermonitors++] = mctx;
8931   PetscFunctionReturn(PETSC_SUCCESS);
8932 }
8933 
8934 /*@
8935   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8936 
8937   Logically Collective
8938 
8939   Input Parameter:
8940 . dm - the DM
8941 
8942   Options Database Key:
8943 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8944   into a code by calls to `DMonitorSet()`, but does not cancel those
8945   set via the options database
8946 
8947   Level: intermediate
8948 
8949   Note:
8950   There is no way to clear one specific monitor from a `DM` object.
8951 
8952 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8953 @*/
8954 PetscErrorCode DMMonitorCancel(DM dm)
8955 {
8956   PetscInt m;
8957 
8958   PetscFunctionBegin;
8959   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8960   for (m = 0; m < dm->numbermonitors; ++m) {
8961     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8962   }
8963   dm->numbermonitors = 0;
8964   PetscFunctionReturn(PETSC_SUCCESS);
8965 }
8966 
8967 /*@C
8968   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8969 
8970   Collective
8971 
8972   Input Parameters:
8973 + dm           - `DM` object you wish to monitor
8974 . name         - the monitor type one is seeking
8975 . help         - message indicating what monitoring is done
8976 . manual       - manual page for the monitor
8977 . monitor      - the monitor function, this must use a `PetscViewerFormat` as its context
8978 - 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
8979 
8980   Output Parameter:
8981 . flg - Flag set if the monitor was created
8982 
8983   Level: developer
8984 
8985 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8986           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8987           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
8988           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8989           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8990           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8991           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8992 @*/
8993 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8994 {
8995   PetscViewer       viewer;
8996   PetscViewerFormat format;
8997 
8998   PetscFunctionBegin;
8999   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9000   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
9001   if (*flg) {
9002     PetscViewerAndFormat *vf;
9003 
9004     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
9005     PetscCall(PetscViewerDestroy(&viewer));
9006     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
9007     PetscCall(DMMonitorSet(dm, monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
9008   }
9009   PetscFunctionReturn(PETSC_SUCCESS);
9010 }
9011 
9012 /*@
9013   DMMonitor - runs the user provided monitor routines, if they exist
9014 
9015   Collective
9016 
9017   Input Parameter:
9018 . dm - The `DM`
9019 
9020   Level: developer
9021 
9022   Developer Note:
9023   Note should indicate when during the life of the `DM` the monitor is run. It appears to be
9024   related to the discretization process seems rather specialized since some `DM` have no
9025   concept of discretization.
9026 
9027 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
9028 @*/
9029 PetscErrorCode DMMonitor(DM dm)
9030 {
9031   PetscInt m;
9032 
9033   PetscFunctionBegin;
9034   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
9035   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9036   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9037   PetscFunctionReturn(PETSC_SUCCESS);
9038 }
9039 
9040 /*@
9041   DMComputeError - Computes the error assuming the user has provided the exact solution functions
9042 
9043   Collective
9044 
9045   Input Parameters:
9046 + dm  - The `DM`
9047 - sol - The solution vector
9048 
9049   Input/Output Parameter:
9050 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
9051            contains the error in each field
9052 
9053   Output Parameter:
9054 . errorVec - A vector to hold the cellwise error (may be `NULL`)
9055 
9056   Level: developer
9057 
9058   Note:
9059   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
9060 
9061 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9062 @*/
9063 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9064 {
9065   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9066   void    **ctxs;
9067   PetscReal time;
9068   PetscInt  Nf, f, Nds, s;
9069 
9070   PetscFunctionBegin;
9071   PetscCall(DMGetNumFields(dm, &Nf));
9072   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9073   PetscCall(DMGetNumDS(dm, &Nds));
9074   for (s = 0; s < Nds; ++s) {
9075     PetscDS         ds;
9076     DMLabel         label;
9077     IS              fieldIS;
9078     const PetscInt *fields;
9079     PetscInt        dsNf;
9080 
9081     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
9082     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9083     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9084     for (f = 0; f < dsNf; ++f) {
9085       const PetscInt field = fields[f];
9086       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9087     }
9088     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9089   }
9090   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);
9091   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9092   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9093   if (errorVec) {
9094     DM             edm;
9095     DMPolytopeType ct;
9096     PetscBool      simplex;
9097     PetscInt       dim, cStart, Nf;
9098 
9099     PetscCall(DMClone(dm, &edm));
9100     PetscCall(DMGetDimension(edm, &dim));
9101     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9102     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9103     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9104     PetscCall(DMGetNumFields(dm, &Nf));
9105     for (f = 0; f < Nf; ++f) {
9106       PetscFE         fe, efe;
9107       PetscQuadrature q;
9108       const char     *name;
9109 
9110       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
9111       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9112       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
9113       PetscCall(PetscObjectSetName((PetscObject)efe, name));
9114       PetscCall(PetscFEGetQuadrature(fe, &q));
9115       PetscCall(PetscFESetQuadrature(efe, q));
9116       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
9117       PetscCall(PetscFEDestroy(&efe));
9118     }
9119     PetscCall(DMCreateDS(edm));
9120 
9121     PetscCall(DMCreateGlobalVector(edm, errorVec));
9122     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
9123     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9124     PetscCall(DMDestroy(&edm));
9125   }
9126   PetscCall(PetscFree2(exactSol, ctxs));
9127   PetscFunctionReturn(PETSC_SUCCESS);
9128 }
9129 
9130 /*@
9131   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
9132 
9133   Not Collective
9134 
9135   Input Parameter:
9136 . dm - The `DM`
9137 
9138   Output Parameter:
9139 . numAux - The number of auxiliary data vectors
9140 
9141   Level: advanced
9142 
9143 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
9144 @*/
9145 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9146 {
9147   PetscFunctionBegin;
9148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9149   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9150   PetscFunctionReturn(PETSC_SUCCESS);
9151 }
9152 
9153 /*@
9154   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9155 
9156   Not Collective
9157 
9158   Input Parameters:
9159 + dm    - The `DM`
9160 . label - The `DMLabel`
9161 . value - The label value indicating the region
9162 - part  - The equation part, or 0 if unused
9163 
9164   Output Parameter:
9165 . aux - The `Vec` holding auxiliary field data
9166 
9167   Level: advanced
9168 
9169   Note:
9170   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9171 
9172 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
9173 @*/
9174 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9175 {
9176   PetscHashAuxKey key, wild = {NULL, 0, 0};
9177   PetscBool       has;
9178 
9179   PetscFunctionBegin;
9180   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9181   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9182   key.label = label;
9183   key.value = value;
9184   key.part  = part;
9185   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9186   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
9187   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9188   PetscFunctionReturn(PETSC_SUCCESS);
9189 }
9190 
9191 /*@
9192   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
9193 
9194   Not Collective because auxiliary vectors are not parallel
9195 
9196   Input Parameters:
9197 + dm    - The `DM`
9198 . label - The `DMLabel`
9199 . value - The label value indicating the region
9200 . part  - The equation part, or 0 if unused
9201 - aux   - The `Vec` holding auxiliary field data
9202 
9203   Level: advanced
9204 
9205 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
9206 @*/
9207 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9208 {
9209   Vec             old;
9210   PetscHashAuxKey key;
9211 
9212   PetscFunctionBegin;
9213   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9214   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9215   key.label = label;
9216   key.value = value;
9217   key.part  = part;
9218   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9219   PetscCall(PetscObjectReference((PetscObject)aux));
9220   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9221   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9222   PetscCall(VecDestroy(&old));
9223   PetscFunctionReturn(PETSC_SUCCESS);
9224 }
9225 
9226 /*@
9227   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9228 
9229   Not Collective
9230 
9231   Input Parameter:
9232 . dm - The `DM`
9233 
9234   Output Parameters:
9235 + labels - The `DMLabel`s for each `Vec`
9236 . values - The label values for each `Vec`
9237 - parts  - The equation parts for each `Vec`
9238 
9239   Level: advanced
9240 
9241   Note:
9242   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9243 
9244 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9245 @*/
9246 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9247 {
9248   PetscHashAuxKey *keys;
9249   PetscInt         n, i, off = 0;
9250 
9251   PetscFunctionBegin;
9252   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9253   PetscAssertPointer(labels, 2);
9254   PetscAssertPointer(values, 3);
9255   PetscAssertPointer(parts, 4);
9256   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9257   PetscCall(PetscMalloc1(n, &keys));
9258   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9259   for (i = 0; i < n; ++i) {
9260     labels[i] = keys[i].label;
9261     values[i] = keys[i].value;
9262     parts[i]  = keys[i].part;
9263   }
9264   PetscCall(PetscFree(keys));
9265   PetscFunctionReturn(PETSC_SUCCESS);
9266 }
9267 
9268 /*@
9269   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9270 
9271   Not Collective
9272 
9273   Input Parameter:
9274 . dm - The `DM`
9275 
9276   Output Parameter:
9277 . dmNew - The new `DM`, now with the same auxiliary data
9278 
9279   Level: advanced
9280 
9281   Note:
9282   This is a shallow copy of the auxiliary vectors
9283 
9284 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9285 @*/
9286 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9287 {
9288   PetscFunctionBegin;
9289   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9290   PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2);
9291   if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS);
9292   PetscCall(DMClearAuxiliaryVec(dmNew));
9293 
9294   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9295   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9296   {
9297     Vec     *auxData;
9298     PetscInt n, i, off = 0;
9299 
9300     PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n));
9301     PetscCall(PetscMalloc1(n, &auxData));
9302     PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData));
9303     for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i]));
9304     PetscCall(PetscFree(auxData));
9305   }
9306   PetscFunctionReturn(PETSC_SUCCESS);
9307 }
9308 
9309 /*@
9310   DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one
9311 
9312   Not Collective
9313 
9314   Input Parameter:
9315 . dm - The `DM`
9316 
9317   Level: advanced
9318 
9319 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9320 @*/
9321 PetscErrorCode DMClearAuxiliaryVec(DM dm)
9322 {
9323   Vec     *auxData;
9324   PetscInt n, i, off = 0;
9325 
9326   PetscFunctionBegin;
9327   PetscCall(PetscHMapAuxGetSize(dm->auxData, &n));
9328   PetscCall(PetscMalloc1(n, &auxData));
9329   PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData));
9330   for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i]));
9331   PetscCall(PetscFree(auxData));
9332   PetscCall(PetscHMapAuxDestroy(&dm->auxData));
9333   PetscCall(PetscHMapAuxCreate(&dm->auxData));
9334   PetscFunctionReturn(PETSC_SUCCESS);
9335 }
9336 
9337 /*@
9338   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9339 
9340   Not Collective
9341 
9342   Input Parameters:
9343 + ct         - The `DMPolytopeType`
9344 . sourceCone - The source arrangement of faces
9345 - targetCone - The target arrangement of faces
9346 
9347   Output Parameters:
9348 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9349 - found - Flag indicating that a suitable orientation was found
9350 
9351   Level: advanced
9352 
9353   Note:
9354   An arrangement is a face order combined with an orientation for each face
9355 
9356   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9357   that labels each arrangement (face ordering plus orientation for each face).
9358 
9359   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9360 
9361 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9362 @*/
9363 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9364 {
9365   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9366   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9367   PetscInt       o, c;
9368 
9369   PetscFunctionBegin;
9370   if (!nO) {
9371     *ornt  = 0;
9372     *found = PETSC_TRUE;
9373     PetscFunctionReturn(PETSC_SUCCESS);
9374   }
9375   for (o = -nO; o < nO; ++o) {
9376     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
9377 
9378     for (c = 0; c < cS; ++c)
9379       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9380     if (c == cS) {
9381       *ornt = o;
9382       break;
9383     }
9384   }
9385   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9386   PetscFunctionReturn(PETSC_SUCCESS);
9387 }
9388 
9389 /*@
9390   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9391 
9392   Not Collective
9393 
9394   Input Parameters:
9395 + ct         - The `DMPolytopeType`
9396 . sourceCone - The source arrangement of faces
9397 - targetCone - The target arrangement of faces
9398 
9399   Output Parameter:
9400 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9401 
9402   Level: advanced
9403 
9404   Note:
9405   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9406 
9407   Developer Note:
9408   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9409 
9410 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9411 @*/
9412 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9413 {
9414   PetscBool found;
9415 
9416   PetscFunctionBegin;
9417   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9418   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9419   PetscFunctionReturn(PETSC_SUCCESS);
9420 }
9421 
9422 /*@
9423   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9424 
9425   Not Collective
9426 
9427   Input Parameters:
9428 + ct         - The `DMPolytopeType`
9429 . sourceVert - The source arrangement of vertices
9430 - targetVert - The target arrangement of vertices
9431 
9432   Output Parameters:
9433 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9434 - found - Flag indicating that a suitable orientation was found
9435 
9436   Level: advanced
9437 
9438   Notes:
9439   An arrangement is a vertex order
9440 
9441   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9442   that labels each arrangement (vertex ordering).
9443 
9444   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9445 
9446 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()`
9447 @*/
9448 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9449 {
9450   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9451   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9452   PetscInt       o, c;
9453 
9454   PetscFunctionBegin;
9455   if (!nO) {
9456     *ornt  = 0;
9457     *found = PETSC_TRUE;
9458     PetscFunctionReturn(PETSC_SUCCESS);
9459   }
9460   for (o = -nO; o < nO; ++o) {
9461     const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o);
9462 
9463     for (c = 0; c < cS; ++c)
9464       if (sourceVert[arr[c]] != targetVert[c]) break;
9465     if (c == cS) {
9466       *ornt = o;
9467       break;
9468     }
9469   }
9470   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9471   PetscFunctionReturn(PETSC_SUCCESS);
9472 }
9473 
9474 /*@
9475   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9476 
9477   Not Collective
9478 
9479   Input Parameters:
9480 + ct         - The `DMPolytopeType`
9481 . sourceCone - The source arrangement of vertices
9482 - targetCone - The target arrangement of vertices
9483 
9484   Output Parameter:
9485 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9486 
9487   Level: advanced
9488 
9489   Note:
9490   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9491 
9492   Developer Note:
9493   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9494 
9495 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9496 @*/
9497 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9498 {
9499   PetscBool found;
9500 
9501   PetscFunctionBegin;
9502   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9503   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9504   PetscFunctionReturn(PETSC_SUCCESS);
9505 }
9506 
9507 /*@
9508   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9509 
9510   Not Collective
9511 
9512   Input Parameters:
9513 + ct    - The `DMPolytopeType`
9514 - point - Coordinates of the point
9515 
9516   Output Parameter:
9517 . inside - Flag indicating whether the point is inside the reference cell of given type
9518 
9519   Level: advanced
9520 
9521 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9522 @*/
9523 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9524 {
9525   PetscReal sum = 0.0;
9526   PetscInt  d;
9527 
9528   PetscFunctionBegin;
9529   *inside = PETSC_TRUE;
9530   switch (ct) {
9531   case DM_POLYTOPE_TRIANGLE:
9532   case DM_POLYTOPE_TETRAHEDRON:
9533     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9534       if (point[d] < -1.0) {
9535         *inside = PETSC_FALSE;
9536         break;
9537       }
9538       sum += point[d];
9539     }
9540     if (sum > PETSC_SMALL) {
9541       *inside = PETSC_FALSE;
9542       break;
9543     }
9544     break;
9545   case DM_POLYTOPE_QUADRILATERAL:
9546   case DM_POLYTOPE_HEXAHEDRON:
9547     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9548       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9549         *inside = PETSC_FALSE;
9550         break;
9551       }
9552     break;
9553   default:
9554     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9555   }
9556   PetscFunctionReturn(PETSC_SUCCESS);
9557 }
9558 
9559 /*@
9560   DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default
9561 
9562   Logically collective
9563 
9564   Input Parameters:
9565 + dm      - The DM
9566 - reorder - Flag for reordering
9567 
9568   Level: intermediate
9569 
9570 .seealso: `DMReorderSectionGetDefault()`
9571 @*/
9572 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder)
9573 {
9574   PetscFunctionBegin;
9575   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9576   PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder));
9577   PetscFunctionReturn(PETSC_SUCCESS);
9578 }
9579 
9580 /*@
9581   DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default
9582 
9583   Not collective
9584 
9585   Input Parameter:
9586 . dm - The DM
9587 
9588   Output Parameter:
9589 . reorder - Flag for reordering
9590 
9591   Level: intermediate
9592 
9593 .seealso: `DMReorderSetDefault()`
9594 @*/
9595 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder)
9596 {
9597   PetscFunctionBegin;
9598   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9599   PetscAssertPointer(reorder, 2);
9600   *reorder = DM_REORDER_DEFAULT_NOTSET;
9601   PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder));
9602   PetscFunctionReturn(PETSC_SUCCESS);
9603 }
9604 
9605 /*@
9606   DMReorderSectionSetType - Set the type of local section reordering
9607 
9608   Logically collective
9609 
9610   Input Parameters:
9611 + dm      - The DM
9612 - reorder - The reordering method
9613 
9614   Level: intermediate
9615 
9616 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()`
9617 @*/
9618 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder)
9619 {
9620   PetscFunctionBegin;
9621   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9622   PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder));
9623   PetscFunctionReturn(PETSC_SUCCESS);
9624 }
9625 
9626 /*@
9627   DMReorderSectionGetType - Get the reordering type for the local section
9628 
9629   Not collective
9630 
9631   Input Parameter:
9632 . dm - The DM
9633 
9634   Output Parameter:
9635 . reorder - The reordering method
9636 
9637   Level: intermediate
9638 
9639 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()`
9640 @*/
9641 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder)
9642 {
9643   PetscFunctionBegin;
9644   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9645   PetscAssertPointer(reorder, 2);
9646   *reorder = NULL;
9647   PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder));
9648   PetscFunctionReturn(PETSC_SUCCESS);
9649 }
9650