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