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