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