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