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