xref: /petsc/src/dm/interface/dm.c (revision a370cb8ab0ec859999cdbf41e4e4937db7025e2e)
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
3708 
3709   Level: intermediate
3710 
3711 .seealso: [](ch_dmbase), `DM`, `DMSetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3712 @*/
3713 PetscErrorCode DMSetApplicationContextDestroy(DM dm, PetscErrorCode (*destroy)(void **))
3714 {
3715   PetscFunctionBegin;
3716   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3717   dm->ctxdestroy = destroy;
3718   PetscFunctionReturn(PETSC_SUCCESS);
3719 }
3720 
3721 /*@
3722   DMSetApplicationContext - Set a user context into a `DM` object
3723 
3724   Not Collective
3725 
3726   Input Parameters:
3727 + dm  - the `DM` object
3728 - ctx - the user context
3729 
3730   Level: intermediate
3731 
3732   Notes:
3733   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3734   In a multilevel solver, the user context is shared by all the `DM` in the hierarchy; it is thus not advisable
3735   to store objects that represent discretized quantities inside the context.
3736 
3737 .seealso: [](ch_dmbase), `DM`, `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3738 @*/
3739 PetscErrorCode DMSetApplicationContext(DM dm, void *ctx)
3740 {
3741   PetscFunctionBegin;
3742   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3743   dm->ctx = ctx;
3744   PetscFunctionReturn(PETSC_SUCCESS);
3745 }
3746 
3747 /*@
3748   DMGetApplicationContext - Gets a user context from a `DM` object
3749 
3750   Not Collective
3751 
3752   Input Parameter:
3753 . dm - the `DM` object
3754 
3755   Output Parameter:
3756 . ctx - the user context
3757 
3758   Level: intermediate
3759 
3760   Note:
3761   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3762 
3763 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3764 @*/
3765 PetscErrorCode DMGetApplicationContext(DM dm, void *ctx)
3766 {
3767   PetscFunctionBegin;
3768   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3769   *(void **)ctx = dm->ctx;
3770   PetscFunctionReturn(PETSC_SUCCESS);
3771 }
3772 
3773 /*@C
3774   DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`.
3775 
3776   Logically Collective
3777 
3778   Input Parameters:
3779 + dm - the DM object
3780 - f  - the function that computes variable bounds used by SNESVI (use `NULL` to cancel a previous function that was set)
3781 
3782   Level: intermediate
3783 
3784 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3785          `DMSetJacobian()`
3786 @*/
3787 PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3788 {
3789   PetscFunctionBegin;
3790   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3791   dm->ops->computevariablebounds = f;
3792   PetscFunctionReturn(PETSC_SUCCESS);
3793 }
3794 
3795 /*@
3796   DMHasVariableBounds - does the `DM` object have a variable bounds function?
3797 
3798   Not Collective
3799 
3800   Input Parameter:
3801 . dm - the `DM` object to destroy
3802 
3803   Output Parameter:
3804 . flg - `PETSC_TRUE` if the variable bounds function exists
3805 
3806   Level: developer
3807 
3808 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3809 @*/
3810 PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3811 {
3812   PetscFunctionBegin;
3813   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3814   PetscAssertPointer(flg, 2);
3815   *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3816   PetscFunctionReturn(PETSC_SUCCESS);
3817 }
3818 
3819 /*@
3820   DMComputeVariableBounds - compute variable bounds used by `SNESVI`.
3821 
3822   Logically Collective
3823 
3824   Input Parameter:
3825 . dm - the `DM` object
3826 
3827   Output Parameters:
3828 + xl - lower bound
3829 - xu - upper bound
3830 
3831   Level: advanced
3832 
3833   Note:
3834   This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3835 
3836 .seealso: [](ch_dmbase), `DM`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3837 @*/
3838 PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3839 {
3840   PetscFunctionBegin;
3841   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3842   PetscValidHeaderSpecific(xl, VEC_CLASSID, 2);
3843   PetscValidHeaderSpecific(xu, VEC_CLASSID, 3);
3844   PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3845   PetscFunctionReturn(PETSC_SUCCESS);
3846 }
3847 
3848 /*@
3849   DMHasColoring - does the `DM` object have a method of providing a coloring?
3850 
3851   Not Collective
3852 
3853   Input Parameter:
3854 . dm - the DM object
3855 
3856   Output Parameter:
3857 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.
3858 
3859   Level: developer
3860 
3861 .seealso: [](ch_dmbase), `DM`, `DMCreateColoring()`
3862 @*/
3863 PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3864 {
3865   PetscFunctionBegin;
3866   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3867   PetscAssertPointer(flg, 2);
3868   *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3869   PetscFunctionReturn(PETSC_SUCCESS);
3870 }
3871 
3872 /*@
3873   DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?
3874 
3875   Not Collective
3876 
3877   Input Parameter:
3878 . dm - the `DM` object
3879 
3880   Output Parameter:
3881 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.
3882 
3883   Level: developer
3884 
3885 .seealso: [](ch_dmbase), `DM`, `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3886 @*/
3887 PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3888 {
3889   PetscFunctionBegin;
3890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3891   PetscAssertPointer(flg, 2);
3892   *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3893   PetscFunctionReturn(PETSC_SUCCESS);
3894 }
3895 
3896 /*@
3897   DMHasCreateInjection - does the `DM` object have a method of providing an injection?
3898 
3899   Not Collective
3900 
3901   Input Parameter:
3902 . dm - the `DM` object
3903 
3904   Output Parameter:
3905 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.
3906 
3907   Level: developer
3908 
3909 .seealso: [](ch_dmbase), `DM`, `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3910 @*/
3911 PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3912 {
3913   PetscFunctionBegin;
3914   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3915   PetscAssertPointer(flg, 2);
3916   if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3917   else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3918   PetscFunctionReturn(PETSC_SUCCESS);
3919 }
3920 
3921 PetscFunctionList DMList              = NULL;
3922 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
3923 
3924 /*@
3925   DMSetType - Builds a `DM`, for a particular `DM` implementation.
3926 
3927   Collective
3928 
3929   Input Parameters:
3930 + dm     - The `DM` object
3931 - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`
3932 
3933   Options Database Key:
3934 . -dm_type <type> - Sets the `DM` type; use -help for a list of available types
3935 
3936   Level: intermediate
3937 
3938   Note:
3939   Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPlexCreateBoxMesh()`
3940 
3941 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
3942 @*/
3943 PetscErrorCode DMSetType(DM dm, DMType method)
3944 {
3945   PetscErrorCode (*r)(DM);
3946   PetscBool match;
3947 
3948   PetscFunctionBegin;
3949   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3950   PetscCall(PetscObjectTypeCompare((PetscObject)dm, method, &match));
3951   if (match) PetscFunctionReturn(PETSC_SUCCESS);
3952 
3953   PetscCall(DMRegisterAll());
3954   PetscCall(PetscFunctionListFind(DMList, method, &r));
3955   PetscCheck(r, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3956 
3957   PetscTryTypeMethod(dm, destroy);
3958   PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));
3959   PetscCall(PetscObjectChangeTypeName((PetscObject)dm, method));
3960   PetscCall((*r)(dm));
3961   PetscFunctionReturn(PETSC_SUCCESS);
3962 }
3963 
3964 /*@
3965   DMGetType - Gets the `DM` type name (as a string) from the `DM`.
3966 
3967   Not Collective
3968 
3969   Input Parameter:
3970 . dm - The `DM`
3971 
3972   Output Parameter:
3973 . type - The `DMType` name
3974 
3975   Level: intermediate
3976 
3977 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
3978 @*/
3979 PetscErrorCode DMGetType(DM dm, DMType *type)
3980 {
3981   PetscFunctionBegin;
3982   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3983   PetscAssertPointer(type, 2);
3984   PetscCall(DMRegisterAll());
3985   *type = ((PetscObject)dm)->type_name;
3986   PetscFunctionReturn(PETSC_SUCCESS);
3987 }
3988 
3989 /*@
3990   DMConvert - Converts a `DM` to another `DM`, either of the same or different type.
3991 
3992   Collective
3993 
3994   Input Parameters:
3995 + dm      - the `DM`
3996 - newtype - new `DM` type (use "same" for the same type)
3997 
3998   Output Parameter:
3999 . M - pointer to new `DM`
4000 
4001   Level: intermediate
4002 
4003   Note:
4004   Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
4005   the MPI communicator of the generated `DM` is always the same as the communicator
4006   of the input `DM`.
4007 
4008 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
4009 @*/
4010 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
4011 {
4012   DM        B;
4013   char      convname[256];
4014   PetscBool sametype /*, issame */;
4015 
4016   PetscFunctionBegin;
4017   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4018   PetscValidType(dm, 1);
4019   PetscAssertPointer(M, 3);
4020   PetscCall(PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype));
4021   /* PetscCall(PetscStrcmp(newtype, "same", &issame)); */
4022   if (sametype) {
4023     *M = dm;
4024     PetscCall(PetscObjectReference((PetscObject)dm));
4025     PetscFunctionReturn(PETSC_SUCCESS);
4026   } else {
4027     PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;
4028 
4029     /*
4030        Order of precedence:
4031        1) See if a specialized converter is known to the current DM.
4032        2) See if a specialized converter is known to the desired DM class.
4033        3) See if a good general converter is registered for the desired class
4034        4) See if a good general converter is known for the current matrix.
4035        5) Use a really basic converter.
4036     */
4037 
4038     /* 1) See if a specialized converter is known to the current DM and the desired class */
4039     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4040     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4041     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4042     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4043     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4044     PetscCall(PetscObjectQueryFunction((PetscObject)dm, convname, &conv));
4045     if (conv) goto foundconv;
4046 
4047     /* 2)  See if a specialized converter is known to the desired DM class. */
4048     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &B));
4049     PetscCall(DMSetType(B, newtype));
4050     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4051     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4052     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4053     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4054     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4055     PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4056     if (conv) {
4057       PetscCall(DMDestroy(&B));
4058       goto foundconv;
4059     }
4060 
4061 #if 0
4062     /* 3) See if a good general converter is registered for the desired class */
4063     conv = B->ops->convertfrom;
4064     PetscCall(DMDestroy(&B));
4065     if (conv) goto foundconv;
4066 
4067     /* 4) See if a good general converter is known for the current matrix */
4068     if (dm->ops->convert) {
4069       conv = dm->ops->convert;
4070     }
4071     if (conv) goto foundconv;
4072 #endif
4073 
4074     /* 5) Use a really basic converter. */
4075     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
4076 
4077   foundconv:
4078     PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0));
4079     PetscCall((*conv)(dm, newtype, M));
4080     /* Things that are independent of DM type: We should consult DMClone() here */
4081     {
4082       const PetscReal *maxCell, *Lstart, *L;
4083 
4084       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
4085       PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L));
4086       (*M)->prealloc_only = dm->prealloc_only;
4087       PetscCall(PetscFree((*M)->vectype));
4088       PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype));
4089       PetscCall(PetscFree((*M)->mattype));
4090       PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype));
4091     }
4092     PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0));
4093   }
4094   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4095   PetscFunctionReturn(PETSC_SUCCESS);
4096 }
4097 
4098 /*--------------------------------------------------------------------------------------------------------------------*/
4099 
4100 /*@C
4101   DMRegister -  Adds a new `DM` type implementation
4102 
4103   Not Collective, No Fortran Support
4104 
4105   Input Parameters:
4106 + sname    - The name of a new user-defined creation routine
4107 - function - The creation routine itself
4108 
4109   Level: advanced
4110 
4111   Note:
4112   `DMRegister()` may be called multiple times to add several user-defined `DM`s
4113 
4114   Example Usage:
4115 .vb
4116     DMRegister("my_da", MyDMCreate);
4117 .ve
4118 
4119   Then, your `DM` type can be chosen with the procedural interface via
4120 .vb
4121     DMCreate(MPI_Comm, DM *);
4122     DMSetType(DM,"my_da");
4123 .ve
4124   or at runtime via the option
4125 .vb
4126     -da_type my_da
4127 .ve
4128 
4129 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
4130 @*/
4131 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
4132 {
4133   PetscFunctionBegin;
4134   PetscCall(DMInitializePackage());
4135   PetscCall(PetscFunctionListAdd(&DMList, sname, function));
4136   PetscFunctionReturn(PETSC_SUCCESS);
4137 }
4138 
4139 /*@
4140   DMLoad - Loads a DM that has been stored in binary  with `DMView()`.
4141 
4142   Collective
4143 
4144   Input Parameters:
4145 + newdm  - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4146            some related function before a call to `DMLoad()`.
4147 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4148            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
4149 
4150   Level: intermediate
4151 
4152   Notes:
4153   The type is determined by the data in the file, any type set into the DM before this call is ignored.
4154 
4155   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
4156   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
4157   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
4158 
4159 .seealso: [](ch_dmbase), `DM`, `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4160 @*/
4161 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4162 {
4163   PetscBool isbinary, ishdf5;
4164 
4165   PetscFunctionBegin;
4166   PetscValidHeaderSpecific(newdm, DM_CLASSID, 1);
4167   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4168   PetscCall(PetscViewerCheckReadable(viewer));
4169   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4170   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4171   PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0));
4172   if (isbinary) {
4173     PetscInt classid;
4174     char     type[256];
4175 
4176     PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
4177     PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %d", (int)classid);
4178     PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
4179     PetscCall(DMSetType(newdm, type));
4180     PetscTryTypeMethod(newdm, load, viewer);
4181   } else if (ishdf5) {
4182     PetscTryTypeMethod(newdm, load, viewer);
4183   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4184   PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0));
4185   PetscFunctionReturn(PETSC_SUCCESS);
4186 }
4187 
4188 /* FEM Support */
4189 
4190 PetscErrorCode DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt x[])
4191 {
4192   PetscInt f;
4193 
4194   PetscFunctionBegin;
4195   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4196   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %" PetscInt_FMT " |\n", x[f]));
4197   PetscFunctionReturn(PETSC_SUCCESS);
4198 }
4199 
4200 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4201 {
4202   PetscInt f;
4203 
4204   PetscFunctionBegin;
4205   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4206   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f])));
4207   PetscFunctionReturn(PETSC_SUCCESS);
4208 }
4209 
4210 PetscErrorCode DMPrintCellVectorReal(PetscInt c, const char name[], PetscInt len, const PetscReal x[])
4211 {
4212   PetscInt f;
4213 
4214   PetscFunctionBegin;
4215   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4216   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)x[f]));
4217   PetscFunctionReturn(PETSC_SUCCESS);
4218 }
4219 
4220 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4221 {
4222   PetscInt f, g;
4223 
4224   PetscFunctionBegin;
4225   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4226   for (f = 0; f < rows; ++f) {
4227     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  |"));
4228     for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4229     PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4230   }
4231   PetscFunctionReturn(PETSC_SUCCESS);
4232 }
4233 
4234 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4235 {
4236   PetscInt           localSize, bs;
4237   PetscMPIInt        size;
4238   Vec                x, xglob;
4239   const PetscScalar *xarray;
4240 
4241   PetscFunctionBegin;
4242   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4243   PetscCall(VecDuplicate(X, &x));
4244   PetscCall(VecCopy(X, x));
4245   PetscCall(VecFilter(x, tol));
4246   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4247   if (size > 1) {
4248     PetscCall(VecGetLocalSize(x, &localSize));
4249     PetscCall(VecGetArrayRead(x, &xarray));
4250     PetscCall(VecGetBlockSize(x, &bs));
4251     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4252   } else {
4253     xglob = x;
4254   }
4255   PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4256   if (size > 1) {
4257     PetscCall(VecDestroy(&xglob));
4258     PetscCall(VecRestoreArrayRead(x, &xarray));
4259   }
4260   PetscCall(VecDestroy(&x));
4261   PetscFunctionReturn(PETSC_SUCCESS);
4262 }
4263 
4264 /*@
4265   DMGetSection - Get the `PetscSection` encoding the local data layout for the `DM`.   This is equivalent to `DMGetLocalSection()`. Deprecated in v3.12
4266 
4267   Input Parameter:
4268 . dm - The `DM`
4269 
4270   Output Parameter:
4271 . section - The `PetscSection`
4272 
4273   Options Database Key:
4274 . -dm_petscsection_view - View the `PetscSection` created by the `DM`
4275 
4276   Level: advanced
4277 
4278   Notes:
4279   Use `DMGetLocalSection()` in new code.
4280 
4281   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4282 
4283 .seealso: [](ch_dmbase), `DM`, `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4284 @*/
4285 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4286 {
4287   PetscFunctionBegin;
4288   PetscCall(DMGetLocalSection(dm, section));
4289   PetscFunctionReturn(PETSC_SUCCESS);
4290 }
4291 
4292 /*@
4293   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4294 
4295   Input Parameter:
4296 . dm - The `DM`
4297 
4298   Output Parameter:
4299 . section - The `PetscSection`
4300 
4301   Options Database Key:
4302 . -dm_petscsection_view - View the section created by the `DM`
4303 
4304   Level: intermediate
4305 
4306   Note:
4307   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4308 
4309 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4310 @*/
4311 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4312 {
4313   PetscFunctionBegin;
4314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4315   PetscAssertPointer(section, 2);
4316   if (!dm->localSection && dm->ops->createlocalsection) {
4317     PetscInt d;
4318 
4319     if (dm->setfromoptionscalled) {
4320       PetscObject       obj = (PetscObject)dm;
4321       PetscViewer       viewer;
4322       PetscViewerFormat format;
4323       PetscBool         flg;
4324 
4325       PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4326       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4327       for (d = 0; d < dm->Nds; ++d) {
4328         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4329         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4330       }
4331       if (flg) {
4332         PetscCall(PetscViewerFlush(viewer));
4333         PetscCall(PetscViewerPopFormat(viewer));
4334         PetscCall(PetscViewerDestroy(&viewer));
4335       }
4336     }
4337     PetscUseTypeMethod(dm, createlocalsection);
4338     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4339   }
4340   *section = dm->localSection;
4341   PetscFunctionReturn(PETSC_SUCCESS);
4342 }
4343 
4344 /*@
4345   DMSetSection - Set the `PetscSection` encoding the local data layout for the `DM`.  This is equivalent to `DMSetLocalSection()`. Deprecated in v3.12
4346 
4347   Input Parameters:
4348 + dm      - The `DM`
4349 - section - The `PetscSection`
4350 
4351   Level: advanced
4352 
4353   Notes:
4354   Use `DMSetLocalSection()` in new code.
4355 
4356   Any existing `PetscSection` will be destroyed
4357 
4358 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4359 @*/
4360 PetscErrorCode DMSetSection(DM dm, PetscSection section)
4361 {
4362   PetscFunctionBegin;
4363   PetscCall(DMSetLocalSection(dm, section));
4364   PetscFunctionReturn(PETSC_SUCCESS);
4365 }
4366 
4367 /*@
4368   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4369 
4370   Input Parameters:
4371 + dm      - The `DM`
4372 - section - The `PetscSection`
4373 
4374   Level: intermediate
4375 
4376   Note:
4377   Any existing Section will be destroyed
4378 
4379 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4380 @*/
4381 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4382 {
4383   PetscInt numFields = 0;
4384   PetscInt f;
4385 
4386   PetscFunctionBegin;
4387   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4388   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4389   PetscCall(PetscObjectReference((PetscObject)section));
4390   PetscCall(PetscSectionDestroy(&dm->localSection));
4391   dm->localSection = section;
4392   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4393   if (numFields) {
4394     PetscCall(DMSetNumFields(dm, numFields));
4395     for (f = 0; f < numFields; ++f) {
4396       PetscObject disc;
4397       const char *name;
4398 
4399       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4400       PetscCall(DMGetField(dm, f, NULL, &disc));
4401       PetscCall(PetscObjectSetName(disc, name));
4402     }
4403   }
4404   /* The global section and the SectionSF will be rebuilt
4405      in the next call to DMGetGlobalSection() and DMGetSectionSF(). */
4406   PetscCall(PetscSectionDestroy(&dm->globalSection));
4407   PetscCall(PetscSFDestroy(&dm->sectionSF));
4408   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4409 
4410   /* Clear scratch vectors */
4411   PetscCall(DMClearGlobalVectors(dm));
4412   PetscCall(DMClearLocalVectors(dm));
4413   PetscCall(DMClearNamedGlobalVectors(dm));
4414   PetscCall(DMClearNamedLocalVectors(dm));
4415   PetscFunctionReturn(PETSC_SUCCESS);
4416 }
4417 
4418 /*@C
4419   DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure.
4420 
4421   Input Parameter:
4422 . dm - The `DM`
4423 
4424   Output Parameters:
4425 + perm        - A permutation of the mesh points in the chart
4426 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking
4427 
4428   Level: developer
4429 
4430 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4431 @*/
4432 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts)
4433 {
4434   PetscFunctionBegin;
4435   *perm        = NULL;
4436   *blockStarts = NULL;
4437   PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts);
4438   PetscFunctionReturn(PETSC_SUCCESS);
4439 }
4440 
4441 /*@
4442   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4443 
4444   not Collective
4445 
4446   Input Parameter:
4447 . dm - The `DM`
4448 
4449   Output Parameters:
4450 + 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.
4451 . 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.
4452 - bias    - Vector containing bias to be added to constrained dofs
4453 
4454   Level: advanced
4455 
4456   Note:
4457   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4458 
4459 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4460 @*/
4461 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4462 {
4463   PetscFunctionBegin;
4464   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4465   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4466   if (section) *section = dm->defaultConstraint.section;
4467   if (mat) *mat = dm->defaultConstraint.mat;
4468   if (bias) *bias = dm->defaultConstraint.bias;
4469   PetscFunctionReturn(PETSC_SUCCESS);
4470 }
4471 
4472 /*@
4473   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4474 
4475   Collective
4476 
4477   Input Parameters:
4478 + dm      - The `DM`
4479 . 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).
4480 . 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).
4481 - 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).
4482 
4483   Level: advanced
4484 
4485   Notes:
4486   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()`.
4487 
4488   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.
4489 
4490   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4491 
4492 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4493 @*/
4494 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4495 {
4496   PetscMPIInt result;
4497 
4498   PetscFunctionBegin;
4499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4500   if (section) {
4501     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4502     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4503     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4504   }
4505   if (mat) {
4506     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4507     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4508     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4509   }
4510   if (bias) {
4511     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4512     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4513     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4514   }
4515   PetscCall(PetscObjectReference((PetscObject)section));
4516   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4517   dm->defaultConstraint.section = section;
4518   PetscCall(PetscObjectReference((PetscObject)mat));
4519   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4520   dm->defaultConstraint.mat = mat;
4521   PetscCall(PetscObjectReference((PetscObject)bias));
4522   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4523   dm->defaultConstraint.bias = bias;
4524   PetscFunctionReturn(PETSC_SUCCESS);
4525 }
4526 
4527 #if defined(PETSC_USE_DEBUG)
4528 /*
4529   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4530 
4531   Input Parameters:
4532 + dm - The `DM`
4533 . localSection - `PetscSection` describing the local data layout
4534 - globalSection - `PetscSection` describing the global data layout
4535 
4536   Level: intermediate
4537 
4538 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4539 */
4540 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4541 {
4542   MPI_Comm        comm;
4543   PetscLayout     layout;
4544   const PetscInt *ranges;
4545   PetscInt        pStart, pEnd, p, nroots;
4546   PetscMPIInt     size, rank;
4547   PetscBool       valid = PETSC_TRUE, gvalid;
4548 
4549   PetscFunctionBegin;
4550   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4551   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4552   PetscCallMPI(MPI_Comm_size(comm, &size));
4553   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4554   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4555   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4556   PetscCall(PetscLayoutCreate(comm, &layout));
4557   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4558   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4559   PetscCall(PetscLayoutSetUp(layout));
4560   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4561   for (p = pStart; p < pEnd; ++p) {
4562     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4563 
4564     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4565     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4566     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4567     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4568     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4569     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4570     if (!gdof) continue; /* Censored point */
4571     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4572       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4573       valid = PETSC_FALSE;
4574     }
4575     if (gcdof && (gcdof != cdof)) {
4576       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4577       valid = PETSC_FALSE;
4578     }
4579     if (gdof < 0) {
4580       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4581       for (d = 0; d < gsize; ++d) {
4582         PetscInt offset = -(goff + 1) + d, r;
4583 
4584         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4585         if (r < 0) r = -(r + 2);
4586         if ((r < 0) || (r >= size)) {
4587           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4588           valid = PETSC_FALSE;
4589           break;
4590         }
4591       }
4592     }
4593   }
4594   PetscCall(PetscLayoutDestroy(&layout));
4595   PetscCall(PetscSynchronizedFlush(comm, NULL));
4596   PetscCallMPI(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm));
4597   if (!gvalid) {
4598     PetscCall(DMView(dm, NULL));
4599     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4600   }
4601   PetscFunctionReturn(PETSC_SUCCESS);
4602 }
4603 #endif
4604 
4605 static PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4606 {
4607   PetscErrorCode (*f)(DM, PetscSF *);
4608 
4609   PetscFunctionBegin;
4610   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4611   PetscAssertPointer(sf, 2);
4612   PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4613   if (f) PetscCall(f(dm, sf));
4614   else *sf = dm->sf;
4615   PetscFunctionReturn(PETSC_SUCCESS);
4616 }
4617 
4618 /*@
4619   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4620 
4621   Collective
4622 
4623   Input Parameter:
4624 . dm - The `DM`
4625 
4626   Output Parameter:
4627 . section - The `PetscSection`
4628 
4629   Level: intermediate
4630 
4631   Note:
4632   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4633 
4634 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4635 @*/
4636 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4637 {
4638   PetscFunctionBegin;
4639   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4640   PetscAssertPointer(section, 2);
4641   if (!dm->globalSection) {
4642     PetscSection s;
4643     PetscSF      sf;
4644 
4645     PetscCall(DMGetLocalSection(dm, &s));
4646     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4647     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4648     PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4649     PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4650     PetscCall(PetscLayoutDestroy(&dm->map));
4651     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4652     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4653   }
4654   *section = dm->globalSection;
4655   PetscFunctionReturn(PETSC_SUCCESS);
4656 }
4657 
4658 /*@
4659   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4660 
4661   Input Parameters:
4662 + dm      - The `DM`
4663 - section - The PetscSection, or `NULL`
4664 
4665   Level: intermediate
4666 
4667   Note:
4668   Any existing `PetscSection` will be destroyed
4669 
4670 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4671 @*/
4672 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4673 {
4674   PetscFunctionBegin;
4675   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4676   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4677   PetscCall(PetscObjectReference((PetscObject)section));
4678   PetscCall(PetscSectionDestroy(&dm->globalSection));
4679   dm->globalSection = section;
4680 #if defined(PETSC_USE_DEBUG)
4681   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4682 #endif
4683   /* Clear global scratch vectors and sectionSF */
4684   PetscCall(PetscSFDestroy(&dm->sectionSF));
4685   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4686   PetscCall(DMClearGlobalVectors(dm));
4687   PetscCall(DMClearNamedGlobalVectors(dm));
4688   PetscFunctionReturn(PETSC_SUCCESS);
4689 }
4690 
4691 /*@
4692   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4693   it is created from the default `PetscSection` layouts in the `DM`.
4694 
4695   Input Parameter:
4696 . dm - The `DM`
4697 
4698   Output Parameter:
4699 . sf - The `PetscSF`
4700 
4701   Level: intermediate
4702 
4703   Note:
4704   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4705 
4706 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4707 @*/
4708 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4709 {
4710   PetscInt nroots;
4711 
4712   PetscFunctionBegin;
4713   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4714   PetscAssertPointer(sf, 2);
4715   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4716   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4717   if (nroots < 0) {
4718     PetscSection section, gSection;
4719 
4720     PetscCall(DMGetLocalSection(dm, &section));
4721     if (section) {
4722       PetscCall(DMGetGlobalSection(dm, &gSection));
4723       PetscCall(DMCreateSectionSF(dm, section, gSection));
4724     } else {
4725       *sf = NULL;
4726       PetscFunctionReturn(PETSC_SUCCESS);
4727     }
4728   }
4729   *sf = dm->sectionSF;
4730   PetscFunctionReturn(PETSC_SUCCESS);
4731 }
4732 
4733 /*@
4734   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4735 
4736   Input Parameters:
4737 + dm - The `DM`
4738 - sf - The `PetscSF`
4739 
4740   Level: intermediate
4741 
4742   Note:
4743   Any previous `PetscSF` is destroyed
4744 
4745 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4746 @*/
4747 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4748 {
4749   PetscFunctionBegin;
4750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4751   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4752   PetscCall(PetscObjectReference((PetscObject)sf));
4753   PetscCall(PetscSFDestroy(&dm->sectionSF));
4754   dm->sectionSF = sf;
4755   PetscFunctionReturn(PETSC_SUCCESS);
4756 }
4757 
4758 /*@
4759   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4760   describing the data layout.
4761 
4762   Input Parameters:
4763 + dm            - The `DM`
4764 . localSection  - `PetscSection` describing the local data layout
4765 - globalSection - `PetscSection` describing the global data layout
4766 
4767   Level: developer
4768 
4769   Note:
4770   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4771 
4772   Developer Note:
4773   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4774   directly into the `DM`, perhaps this function should not take the local and global sections as
4775   input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing
4776   they create, this returns nothing
4777 
4778 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4779 @*/
4780 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4781 {
4782   PetscFunctionBegin;
4783   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4784   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4785   PetscFunctionReturn(PETSC_SUCCESS);
4786 }
4787 
4788 /*@
4789   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4790 
4791   Not collective but the resulting `PetscSF` is collective
4792 
4793   Input Parameter:
4794 . dm - The `DM`
4795 
4796   Output Parameter:
4797 . sf - The `PetscSF`
4798 
4799   Level: intermediate
4800 
4801   Note:
4802   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4803 
4804 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4805 @*/
4806 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4807 {
4808   PetscFunctionBegin;
4809   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4810   PetscAssertPointer(sf, 2);
4811   *sf = dm->sf;
4812   PetscFunctionReturn(PETSC_SUCCESS);
4813 }
4814 
4815 /*@
4816   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4817 
4818   Collective
4819 
4820   Input Parameters:
4821 + dm - The `DM`
4822 - sf - The `PetscSF`
4823 
4824   Level: intermediate
4825 
4826 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4827 @*/
4828 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4829 {
4830   PetscFunctionBegin;
4831   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4832   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4833   PetscCall(PetscObjectReference((PetscObject)sf));
4834   PetscCall(PetscSFDestroy(&dm->sf));
4835   dm->sf = sf;
4836   PetscFunctionReturn(PETSC_SUCCESS);
4837 }
4838 
4839 /*@
4840   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4841 
4842   Input Parameter:
4843 . dm - The `DM`
4844 
4845   Output Parameter:
4846 . sf - The `PetscSF`
4847 
4848   Level: intermediate
4849 
4850   Note:
4851   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4852 
4853 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4854 @*/
4855 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4856 {
4857   PetscFunctionBegin;
4858   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4859   PetscAssertPointer(sf, 2);
4860   *sf = dm->sfNatural;
4861   PetscFunctionReturn(PETSC_SUCCESS);
4862 }
4863 
4864 /*@
4865   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4866 
4867   Input Parameters:
4868 + dm - The DM
4869 - sf - The PetscSF
4870 
4871   Level: intermediate
4872 
4873 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4874 @*/
4875 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4876 {
4877   PetscFunctionBegin;
4878   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4879   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4880   PetscCall(PetscObjectReference((PetscObject)sf));
4881   PetscCall(PetscSFDestroy(&dm->sfNatural));
4882   dm->sfNatural = sf;
4883   PetscFunctionReturn(PETSC_SUCCESS);
4884 }
4885 
4886 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4887 {
4888   PetscClassId id;
4889 
4890   PetscFunctionBegin;
4891   PetscCall(PetscObjectGetClassId(disc, &id));
4892   if (id == PETSCFE_CLASSID) {
4893     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4894   } else if (id == PETSCFV_CLASSID) {
4895     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4896   } else {
4897     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4898   }
4899   PetscFunctionReturn(PETSC_SUCCESS);
4900 }
4901 
4902 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4903 {
4904   RegionField *tmpr;
4905   PetscInt     Nf = dm->Nf, f;
4906 
4907   PetscFunctionBegin;
4908   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4909   PetscCall(PetscMalloc1(NfNew, &tmpr));
4910   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4911   for (f = Nf; f < NfNew; ++f) {
4912     tmpr[f].disc        = NULL;
4913     tmpr[f].label       = NULL;
4914     tmpr[f].avoidTensor = PETSC_FALSE;
4915   }
4916   PetscCall(PetscFree(dm->fields));
4917   dm->Nf     = NfNew;
4918   dm->fields = tmpr;
4919   PetscFunctionReturn(PETSC_SUCCESS);
4920 }
4921 
4922 /*@
4923   DMClearFields - Remove all fields from the `DM`
4924 
4925   Logically Collective
4926 
4927   Input Parameter:
4928 . dm - The `DM`
4929 
4930   Level: intermediate
4931 
4932 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4933 @*/
4934 PetscErrorCode DMClearFields(DM dm)
4935 {
4936   PetscInt f;
4937 
4938   PetscFunctionBegin;
4939   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4940   for (f = 0; f < dm->Nf; ++f) {
4941     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4942     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4943   }
4944   PetscCall(PetscFree(dm->fields));
4945   dm->fields = NULL;
4946   dm->Nf     = 0;
4947   PetscFunctionReturn(PETSC_SUCCESS);
4948 }
4949 
4950 /*@
4951   DMGetNumFields - Get the number of fields in the `DM`
4952 
4953   Not Collective
4954 
4955   Input Parameter:
4956 . dm - The `DM`
4957 
4958   Output Parameter:
4959 . numFields - The number of fields
4960 
4961   Level: intermediate
4962 
4963 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4964 @*/
4965 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4966 {
4967   PetscFunctionBegin;
4968   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4969   PetscAssertPointer(numFields, 2);
4970   *numFields = dm->Nf;
4971   PetscFunctionReturn(PETSC_SUCCESS);
4972 }
4973 
4974 /*@
4975   DMSetNumFields - Set the number of fields in the `DM`
4976 
4977   Logically Collective
4978 
4979   Input Parameters:
4980 + dm        - The `DM`
4981 - numFields - The number of fields
4982 
4983   Level: intermediate
4984 
4985 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
4986 @*/
4987 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4988 {
4989   PetscInt Nf, f;
4990 
4991   PetscFunctionBegin;
4992   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4993   PetscCall(DMGetNumFields(dm, &Nf));
4994   for (f = Nf; f < numFields; ++f) {
4995     PetscContainer obj;
4996 
4997     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
4998     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
4999     PetscCall(PetscContainerDestroy(&obj));
5000   }
5001   PetscFunctionReturn(PETSC_SUCCESS);
5002 }
5003 
5004 /*@
5005   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
5006 
5007   Not Collective
5008 
5009   Input Parameters:
5010 + dm - The `DM`
5011 - f  - The field number
5012 
5013   Output Parameters:
5014 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
5015 - disc  - The discretization object (pass in `NULL` if not needed)
5016 
5017   Level: intermediate
5018 
5019 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
5020 @*/
5021 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
5022 {
5023   PetscFunctionBegin;
5024   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5025   PetscAssertPointer(disc, 4);
5026   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);
5027   if (label) *label = dm->fields[f].label;
5028   if (disc) *disc = dm->fields[f].disc;
5029   PetscFunctionReturn(PETSC_SUCCESS);
5030 }
5031 
5032 /* Does not clear the DS */
5033 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5034 {
5035   PetscFunctionBegin;
5036   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
5037   PetscCall(DMLabelDestroy(&dm->fields[f].label));
5038   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
5039   dm->fields[f].label = label;
5040   dm->fields[f].disc  = disc;
5041   PetscCall(PetscObjectReference((PetscObject)label));
5042   PetscCall(PetscObjectReference((PetscObject)disc));
5043   PetscFunctionReturn(PETSC_SUCCESS);
5044 }
5045 
5046 /*@
5047   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
5048   the field numbering.
5049 
5050   Logically Collective
5051 
5052   Input Parameters:
5053 + dm    - The `DM`
5054 . f     - The field number
5055 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5056 - disc  - The discretization object
5057 
5058   Level: intermediate
5059 
5060 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
5061 @*/
5062 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5063 {
5064   PetscFunctionBegin;
5065   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5066   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5067   PetscValidHeader(disc, 4);
5068   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
5069   PetscCall(DMSetField_Internal(dm, f, label, disc));
5070   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
5071   PetscCall(DMClearDS(dm));
5072   PetscFunctionReturn(PETSC_SUCCESS);
5073 }
5074 
5075 /*@
5076   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
5077   and a discretization object that defines the function space associated with those points.
5078 
5079   Logically Collective
5080 
5081   Input Parameters:
5082 + dm    - The `DM`
5083 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5084 - disc  - The discretization object
5085 
5086   Level: intermediate
5087 
5088   Notes:
5089   The label already exists or will be added to the `DM` with `DMSetLabel()`.
5090 
5091   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
5092   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
5093   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5094 
5095 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5096 @*/
5097 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5098 {
5099   PetscInt Nf = dm->Nf;
5100 
5101   PetscFunctionBegin;
5102   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5103   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5104   PetscValidHeader(disc, 3);
5105   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5106   dm->fields[Nf].label = label;
5107   dm->fields[Nf].disc  = disc;
5108   PetscCall(PetscObjectReference((PetscObject)label));
5109   PetscCall(PetscObjectReference((PetscObject)disc));
5110   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5111   PetscCall(DMClearDS(dm));
5112   PetscFunctionReturn(PETSC_SUCCESS);
5113 }
5114 
5115 /*@
5116   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5117 
5118   Logically Collective
5119 
5120   Input Parameters:
5121 + dm          - The `DM`
5122 . f           - The field index
5123 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5124 
5125   Level: intermediate
5126 
5127 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5128 @*/
5129 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5130 {
5131   PetscFunctionBegin;
5132   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);
5133   dm->fields[f].avoidTensor = avoidTensor;
5134   PetscFunctionReturn(PETSC_SUCCESS);
5135 }
5136 
5137 /*@
5138   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5139 
5140   Not Collective
5141 
5142   Input Parameters:
5143 + dm - The `DM`
5144 - f  - The field index
5145 
5146   Output Parameter:
5147 . avoidTensor - The flag to avoid defining the field on tensor cells
5148 
5149   Level: intermediate
5150 
5151 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5152 @*/
5153 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5154 {
5155   PetscFunctionBegin;
5156   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);
5157   *avoidTensor = dm->fields[f].avoidTensor;
5158   PetscFunctionReturn(PETSC_SUCCESS);
5159 }
5160 
5161 /*@
5162   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5163 
5164   Collective
5165 
5166   Input Parameters:
5167 + dm        - The `DM`
5168 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
5169 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
5170 
5171   Output Parameter:
5172 . newdm - The `DM`
5173 
5174   Level: advanced
5175 
5176 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5177 @*/
5178 PetscErrorCode DMCopyFields(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
5179 {
5180   PetscInt Nf, f;
5181 
5182   PetscFunctionBegin;
5183   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5184   PetscCall(DMGetNumFields(dm, &Nf));
5185   PetscCall(DMClearFields(newdm));
5186   for (f = 0; f < Nf; ++f) {
5187     DMLabel      label;
5188     PetscObject  field;
5189     PetscClassId id;
5190     PetscBool    useCone, useClosure;
5191 
5192     PetscCall(DMGetField(dm, f, &label, &field));
5193     PetscCall(PetscObjectGetClassId(field, &id));
5194     if (id == PETSCFE_CLASSID) {
5195       PetscFE newfe;
5196 
5197       PetscCall(PetscFELimitDegree((PetscFE)field, minDegree, maxDegree, &newfe));
5198       PetscCall(DMSetField(newdm, f, label, (PetscObject)newfe));
5199       PetscCall(PetscFEDestroy(&newfe));
5200     } else {
5201       PetscCall(DMSetField(newdm, f, label, field));
5202     }
5203     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5204     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5205   }
5206   PetscFunctionReturn(PETSC_SUCCESS);
5207 }
5208 
5209 /*@
5210   DMGetAdjacency - Returns the flags for determining variable influence
5211 
5212   Not Collective
5213 
5214   Input Parameters:
5215 + dm - The `DM` object
5216 - f  - The field number, or `PETSC_DEFAULT` for the default adjacency
5217 
5218   Output Parameters:
5219 + useCone    - Flag for variable influence starting with the cone operation
5220 - useClosure - Flag for variable influence using transitive closure
5221 
5222   Level: developer
5223 
5224   Notes:
5225 .vb
5226      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5227      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5228      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5229 .ve
5230   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5231 
5232 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5233 @*/
5234 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5235 {
5236   PetscFunctionBegin;
5237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5238   if (useCone) PetscAssertPointer(useCone, 3);
5239   if (useClosure) PetscAssertPointer(useClosure, 4);
5240   if (f < 0) {
5241     if (useCone) *useCone = dm->adjacency[0];
5242     if (useClosure) *useClosure = dm->adjacency[1];
5243   } else {
5244     PetscInt Nf;
5245 
5246     PetscCall(DMGetNumFields(dm, &Nf));
5247     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5248     if (useCone) *useCone = dm->fields[f].adjacency[0];
5249     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5250   }
5251   PetscFunctionReturn(PETSC_SUCCESS);
5252 }
5253 
5254 /*@
5255   DMSetAdjacency - Set the flags for determining variable influence
5256 
5257   Not Collective
5258 
5259   Input Parameters:
5260 + dm         - The `DM` object
5261 . f          - The field number
5262 . useCone    - Flag for variable influence starting with the cone operation
5263 - useClosure - Flag for variable influence using transitive closure
5264 
5265   Level: developer
5266 
5267   Notes:
5268 .vb
5269      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5270      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5271      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5272 .ve
5273   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5274 
5275 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5276 @*/
5277 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5278 {
5279   PetscFunctionBegin;
5280   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5281   if (f < 0) {
5282     dm->adjacency[0] = useCone;
5283     dm->adjacency[1] = useClosure;
5284   } else {
5285     PetscInt Nf;
5286 
5287     PetscCall(DMGetNumFields(dm, &Nf));
5288     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5289     dm->fields[f].adjacency[0] = useCone;
5290     dm->fields[f].adjacency[1] = useClosure;
5291   }
5292   PetscFunctionReturn(PETSC_SUCCESS);
5293 }
5294 
5295 /*@
5296   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5297 
5298   Not collective
5299 
5300   Input Parameter:
5301 . dm - The `DM` object
5302 
5303   Output Parameters:
5304 + useCone    - Flag for variable influence starting with the cone operation
5305 - useClosure - Flag for variable influence using transitive closure
5306 
5307   Level: developer
5308 
5309   Notes:
5310 .vb
5311      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5312      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5313      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5314 .ve
5315 
5316 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5317 @*/
5318 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5319 {
5320   PetscInt Nf;
5321 
5322   PetscFunctionBegin;
5323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5324   if (useCone) PetscAssertPointer(useCone, 2);
5325   if (useClosure) PetscAssertPointer(useClosure, 3);
5326   PetscCall(DMGetNumFields(dm, &Nf));
5327   if (!Nf) {
5328     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5329   } else {
5330     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5331   }
5332   PetscFunctionReturn(PETSC_SUCCESS);
5333 }
5334 
5335 /*@
5336   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5337 
5338   Not Collective
5339 
5340   Input Parameters:
5341 + dm         - The `DM` object
5342 . useCone    - Flag for variable influence starting with the cone operation
5343 - useClosure - Flag for variable influence using transitive closure
5344 
5345   Level: developer
5346 
5347   Notes:
5348 .vb
5349      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5350      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5351      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5352 .ve
5353 
5354 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5355 @*/
5356 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5357 {
5358   PetscInt Nf;
5359 
5360   PetscFunctionBegin;
5361   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5362   PetscCall(DMGetNumFields(dm, &Nf));
5363   if (!Nf) {
5364     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5365   } else {
5366     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5367   }
5368   PetscFunctionReturn(PETSC_SUCCESS);
5369 }
5370 
5371 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5372 {
5373   DM           plex;
5374   DMLabel     *labels, *glabels;
5375   const char **names;
5376   char        *sendNames, *recvNames;
5377   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5378   size_t       len;
5379   MPI_Comm     comm;
5380   PetscMPIInt  rank, size, p, *counts, *displs;
5381 
5382   PetscFunctionBegin;
5383   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5384   PetscCallMPI(MPI_Comm_size(comm, &size));
5385   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5386   PetscCall(DMGetNumDS(dm, &Nds));
5387   for (s = 0; s < Nds; ++s) {
5388     PetscDS  dsBC;
5389     PetscInt numBd;
5390 
5391     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5392     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5393     maxLabels += numBd;
5394   }
5395   PetscCall(PetscCalloc1(maxLabels, &labels));
5396   /* Get list of labels to be completed */
5397   for (s = 0; s < Nds; ++s) {
5398     PetscDS  dsBC;
5399     PetscInt numBd, bd;
5400 
5401     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5402     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5403     for (bd = 0; bd < numBd; ++bd) {
5404       DMLabel      label;
5405       PetscInt     field;
5406       PetscObject  obj;
5407       PetscClassId id;
5408 
5409       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5410       PetscCall(DMGetField(dm, field, NULL, &obj));
5411       PetscCall(PetscObjectGetClassId(obj, &id));
5412       if (!(id == PETSCFE_CLASSID) || !label) continue;
5413       for (l = 0; l < Nl; ++l)
5414         if (labels[l] == label) break;
5415       if (l == Nl) labels[Nl++] = label;
5416     }
5417   }
5418   /* Get label names */
5419   PetscCall(PetscMalloc1(Nl, &names));
5420   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5421   for (l = 0; l < Nl; ++l) {
5422     PetscCall(PetscStrlen(names[l], &len));
5423     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5424   }
5425   PetscCall(PetscFree(labels));
5426   PetscCallMPI(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5427   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5428   for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5429   PetscCall(PetscFree(names));
5430   /* Put all names on all processes */
5431   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5432   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5433   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5434   gNl = displs[size];
5435   for (p = 0; p < size; ++p) {
5436     counts[p] *= gmaxLen;
5437     displs[p] *= gmaxLen;
5438   }
5439   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5440   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5441   PetscCall(PetscFree2(counts, displs));
5442   PetscCall(PetscFree(sendNames));
5443   for (l = 0, gl = 0; l < gNl; ++l) {
5444     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5445     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5446     for (m = 0; m < gl; ++m)
5447       if (glabels[m] == glabels[gl]) goto next_label;
5448     PetscCall(DMConvert(dm, DMPLEX, &plex));
5449     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5450     PetscCall(DMDestroy(&plex));
5451     ++gl;
5452   next_label:
5453     continue;
5454   }
5455   PetscCall(PetscFree2(recvNames, glabels));
5456   PetscFunctionReturn(PETSC_SUCCESS);
5457 }
5458 
5459 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5460 {
5461   DMSpace *tmpd;
5462   PetscInt Nds = dm->Nds, s;
5463 
5464   PetscFunctionBegin;
5465   if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5466   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5467   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5468   for (s = Nds; s < NdsNew; ++s) {
5469     tmpd[s].ds     = NULL;
5470     tmpd[s].label  = NULL;
5471     tmpd[s].fields = NULL;
5472   }
5473   PetscCall(PetscFree(dm->probs));
5474   dm->Nds   = NdsNew;
5475   dm->probs = tmpd;
5476   PetscFunctionReturn(PETSC_SUCCESS);
5477 }
5478 
5479 /*@
5480   DMGetNumDS - Get the number of discrete systems in the `DM`
5481 
5482   Not Collective
5483 
5484   Input Parameter:
5485 . dm - The `DM`
5486 
5487   Output Parameter:
5488 . Nds - The number of `PetscDS` objects
5489 
5490   Level: intermediate
5491 
5492 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5493 @*/
5494 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5495 {
5496   PetscFunctionBegin;
5497   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5498   PetscAssertPointer(Nds, 2);
5499   *Nds = dm->Nds;
5500   PetscFunctionReturn(PETSC_SUCCESS);
5501 }
5502 
5503 /*@
5504   DMClearDS - Remove all discrete systems from the `DM`
5505 
5506   Logically Collective
5507 
5508   Input Parameter:
5509 . dm - The `DM`
5510 
5511   Level: intermediate
5512 
5513 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5514 @*/
5515 PetscErrorCode DMClearDS(DM dm)
5516 {
5517   PetscInt s;
5518 
5519   PetscFunctionBegin;
5520   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5521   for (s = 0; s < dm->Nds; ++s) {
5522     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5523     PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5524     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5525     PetscCall(ISDestroy(&dm->probs[s].fields));
5526   }
5527   PetscCall(PetscFree(dm->probs));
5528   dm->probs = NULL;
5529   dm->Nds   = 0;
5530   PetscFunctionReturn(PETSC_SUCCESS);
5531 }
5532 
5533 /*@
5534   DMGetDS - Get the default `PetscDS`
5535 
5536   Not Collective
5537 
5538   Input Parameter:
5539 . dm - The `DM`
5540 
5541   Output Parameter:
5542 . ds - The default `PetscDS`
5543 
5544   Level: intermediate
5545 
5546 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5547 @*/
5548 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5549 {
5550   PetscFunctionBeginHot;
5551   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5552   PetscAssertPointer(ds, 2);
5553   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5554   *ds = dm->probs[0].ds;
5555   PetscFunctionReturn(PETSC_SUCCESS);
5556 }
5557 
5558 /*@
5559   DMGetCellDS - Get the `PetscDS` defined on a given cell
5560 
5561   Not Collective
5562 
5563   Input Parameters:
5564 + dm    - The `DM`
5565 - point - Cell for the `PetscDS`
5566 
5567   Output Parameters:
5568 + ds   - The `PetscDS` defined on the given cell
5569 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds
5570 
5571   Level: developer
5572 
5573 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5574 @*/
5575 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5576 {
5577   PetscDS  dsDef = NULL;
5578   PetscInt s;
5579 
5580   PetscFunctionBeginHot;
5581   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5582   if (ds) PetscAssertPointer(ds, 3);
5583   if (dsIn) PetscAssertPointer(dsIn, 4);
5584   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5585   if (ds) *ds = NULL;
5586   if (dsIn) *dsIn = NULL;
5587   for (s = 0; s < dm->Nds; ++s) {
5588     PetscInt val;
5589 
5590     if (!dm->probs[s].label) {
5591       dsDef = dm->probs[s].ds;
5592     } else {
5593       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5594       if (val >= 0) {
5595         if (ds) *ds = dm->probs[s].ds;
5596         if (dsIn) *dsIn = dm->probs[s].dsIn;
5597         break;
5598       }
5599     }
5600   }
5601   if (ds && !*ds) *ds = dsDef;
5602   PetscFunctionReturn(PETSC_SUCCESS);
5603 }
5604 
5605 /*@
5606   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5607 
5608   Not Collective
5609 
5610   Input Parameters:
5611 + dm    - The `DM`
5612 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5613 
5614   Output Parameters:
5615 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5616 . ds     - The `PetscDS` defined on the given region, or `NULL`
5617 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5618 
5619   Level: advanced
5620 
5621   Note:
5622   If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5623   the `PetscDS` for the full domain (if present) is returned. Returns with
5624   fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5625 
5626 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5627 @*/
5628 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5629 {
5630   PetscInt Nds = dm->Nds, s;
5631 
5632   PetscFunctionBegin;
5633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5634   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5635   if (fields) {
5636     PetscAssertPointer(fields, 3);
5637     *fields = NULL;
5638   }
5639   if (ds) {
5640     PetscAssertPointer(ds, 4);
5641     *ds = NULL;
5642   }
5643   if (dsIn) {
5644     PetscAssertPointer(dsIn, 5);
5645     *dsIn = NULL;
5646   }
5647   for (s = 0; s < Nds; ++s) {
5648     if (dm->probs[s].label == label || !dm->probs[s].label) {
5649       if (fields) *fields = dm->probs[s].fields;
5650       if (ds) *ds = dm->probs[s].ds;
5651       if (dsIn) *dsIn = dm->probs[s].dsIn;
5652       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5653     }
5654   }
5655   PetscFunctionReturn(PETSC_SUCCESS);
5656 }
5657 
5658 /*@
5659   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5660 
5661   Collective
5662 
5663   Input Parameters:
5664 + dm     - The `DM`
5665 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5666 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5667 . ds     - The `PetscDS` defined on the given region
5668 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5669 
5670   Level: advanced
5671 
5672   Note:
5673   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5674   the fields argument is ignored.
5675 
5676 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5677 @*/
5678 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5679 {
5680   PetscInt Nds = dm->Nds, s;
5681 
5682   PetscFunctionBegin;
5683   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5684   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5685   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5686   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5687   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5688   for (s = 0; s < Nds; ++s) {
5689     if (dm->probs[s].label == label) {
5690       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5691       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5692       dm->probs[s].ds   = ds;
5693       dm->probs[s].dsIn = dsIn;
5694       PetscFunctionReturn(PETSC_SUCCESS);
5695     }
5696   }
5697   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5698   PetscCall(PetscObjectReference((PetscObject)label));
5699   PetscCall(PetscObjectReference((PetscObject)fields));
5700   PetscCall(PetscObjectReference((PetscObject)ds));
5701   PetscCall(PetscObjectReference((PetscObject)dsIn));
5702   if (!label) {
5703     /* Put the NULL label at the front, so it is returned as the default */
5704     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5705     Nds = 0;
5706   }
5707   dm->probs[Nds].label  = label;
5708   dm->probs[Nds].fields = fields;
5709   dm->probs[Nds].ds     = ds;
5710   dm->probs[Nds].dsIn   = dsIn;
5711   PetscFunctionReturn(PETSC_SUCCESS);
5712 }
5713 
5714 /*@
5715   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5716 
5717   Not Collective
5718 
5719   Input Parameters:
5720 + dm  - The `DM`
5721 - num - The region number, in [0, Nds)
5722 
5723   Output Parameters:
5724 + label  - The region label, or `NULL`
5725 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5726 . ds     - The `PetscDS` defined on the given region, or `NULL`
5727 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5728 
5729   Level: advanced
5730 
5731 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5732 @*/
5733 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5734 {
5735   PetscInt Nds;
5736 
5737   PetscFunctionBegin;
5738   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5739   PetscCall(DMGetNumDS(dm, &Nds));
5740   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5741   if (label) {
5742     PetscAssertPointer(label, 3);
5743     *label = dm->probs[num].label;
5744   }
5745   if (fields) {
5746     PetscAssertPointer(fields, 4);
5747     *fields = dm->probs[num].fields;
5748   }
5749   if (ds) {
5750     PetscAssertPointer(ds, 5);
5751     *ds = dm->probs[num].ds;
5752   }
5753   if (dsIn) {
5754     PetscAssertPointer(dsIn, 6);
5755     *dsIn = dm->probs[num].dsIn;
5756   }
5757   PetscFunctionReturn(PETSC_SUCCESS);
5758 }
5759 
5760 /*@
5761   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5762 
5763   Not Collective
5764 
5765   Input Parameters:
5766 + dm     - The `DM`
5767 . num    - The region number, in [0, Nds)
5768 . label  - The region label, or `NULL`
5769 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5770 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5771 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5772 
5773   Level: advanced
5774 
5775 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5776 @*/
5777 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5778 {
5779   PetscInt Nds;
5780 
5781   PetscFunctionBegin;
5782   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5783   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5784   PetscCall(DMGetNumDS(dm, &Nds));
5785   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5786   PetscCall(PetscObjectReference((PetscObject)label));
5787   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5788   dm->probs[num].label = label;
5789   if (fields) {
5790     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5791     PetscCall(PetscObjectReference((PetscObject)fields));
5792     PetscCall(ISDestroy(&dm->probs[num].fields));
5793     dm->probs[num].fields = fields;
5794   }
5795   if (ds) {
5796     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5797     PetscCall(PetscObjectReference((PetscObject)ds));
5798     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5799     dm->probs[num].ds = ds;
5800   }
5801   if (dsIn) {
5802     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5803     PetscCall(PetscObjectReference((PetscObject)dsIn));
5804     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5805     dm->probs[num].dsIn = dsIn;
5806   }
5807   PetscFunctionReturn(PETSC_SUCCESS);
5808 }
5809 
5810 /*@
5811   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5812 
5813   Not Collective
5814 
5815   Input Parameters:
5816 + dm - The `DM`
5817 - ds - The `PetscDS` defined on the given region
5818 
5819   Output Parameter:
5820 . num - The region number, in [0, Nds), or -1 if not found
5821 
5822   Level: advanced
5823 
5824 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5825 @*/
5826 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5827 {
5828   PetscInt Nds, n;
5829 
5830   PetscFunctionBegin;
5831   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5832   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5833   PetscAssertPointer(num, 3);
5834   PetscCall(DMGetNumDS(dm, &Nds));
5835   for (n = 0; n < Nds; ++n)
5836     if (ds == dm->probs[n].ds) break;
5837   if (n >= Nds) *num = -1;
5838   else *num = n;
5839   PetscFunctionReturn(PETSC_SUCCESS);
5840 }
5841 
5842 /*@
5843   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5844 
5845   Not Collective
5846 
5847   Input Parameters:
5848 + dm     - The `DM`
5849 . Nc     - The number of components for the field
5850 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5851 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5852 
5853   Output Parameter:
5854 . fem - The `PetscFE`
5855 
5856   Level: intermediate
5857 
5858   Note:
5859   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5860 
5861 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5862 @*/
5863 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5864 {
5865   DMPolytopeType ct;
5866   PetscInt       dim, cStart;
5867 
5868   PetscFunctionBegin;
5869   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5870   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5871   if (prefix) PetscAssertPointer(prefix, 3);
5872   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5873   PetscAssertPointer(fem, 5);
5874   PetscCall(DMGetDimension(dm, &dim));
5875   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5876   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5877   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5878   PetscFunctionReturn(PETSC_SUCCESS);
5879 }
5880 
5881 /*@
5882   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5883 
5884   Collective
5885 
5886   Input Parameter:
5887 . dm - The `DM`
5888 
5889   Options Database Key:
5890 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5891 
5892   Level: intermediate
5893 
5894 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5895 @*/
5896 PetscErrorCode DMCreateDS(DM dm)
5897 {
5898   MPI_Comm  comm;
5899   PetscDS   dsDef;
5900   DMLabel  *labelSet;
5901   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5902   PetscBool doSetup = PETSC_TRUE, flg;
5903 
5904   PetscFunctionBegin;
5905   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5906   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5907   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5908   PetscCall(DMGetCoordinateDim(dm, &dE));
5909   /* Determine how many regions we have */
5910   PetscCall(PetscMalloc1(Nf, &labelSet));
5911   Nl   = 0;
5912   Ndef = 0;
5913   for (f = 0; f < Nf; ++f) {
5914     DMLabel  label = dm->fields[f].label;
5915     PetscInt l;
5916 
5917 #ifdef PETSC_HAVE_LIBCEED
5918     /* Move CEED context to discretizations */
5919     {
5920       PetscClassId id;
5921 
5922       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5923       if (id == PETSCFE_CLASSID) {
5924         Ceed ceed;
5925 
5926         PetscCall(DMGetCeed(dm, &ceed));
5927         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5928       }
5929     }
5930 #endif
5931     if (!label) {
5932       ++Ndef;
5933       continue;
5934     }
5935     for (l = 0; l < Nl; ++l)
5936       if (label == labelSet[l]) break;
5937     if (l < Nl) continue;
5938     labelSet[Nl++] = label;
5939   }
5940   /* Create default DS if there are no labels to intersect with */
5941   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5942   if (!dsDef && Ndef && !Nl) {
5943     IS        fields;
5944     PetscInt *fld, nf;
5945 
5946     for (f = 0, nf = 0; f < Nf; ++f)
5947       if (!dm->fields[f].label) ++nf;
5948     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5949     PetscCall(PetscMalloc1(nf, &fld));
5950     for (f = 0, nf = 0; f < Nf; ++f)
5951       if (!dm->fields[f].label) fld[nf++] = f;
5952     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5953     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5954     PetscCall(ISSetType(fields, ISGENERAL));
5955     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5956 
5957     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5958     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5959     PetscCall(PetscDSDestroy(&dsDef));
5960     PetscCall(ISDestroy(&fields));
5961   }
5962   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5963   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5964   /* Intersect labels with default fields */
5965   if (Ndef && Nl) {
5966     DM              plex;
5967     DMLabel         cellLabel;
5968     IS              fieldIS, allcellIS, defcellIS = NULL;
5969     PetscInt       *fields;
5970     const PetscInt *cells;
5971     PetscInt        depth, nf = 0, n, c;
5972 
5973     PetscCall(DMConvert(dm, DMPLEX, &plex));
5974     PetscCall(DMPlexGetDepth(plex, &depth));
5975     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5976     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5977     /* TODO This looks like it only works for one label */
5978     for (l = 0; l < Nl; ++l) {
5979       DMLabel label = labelSet[l];
5980       IS      pointIS;
5981 
5982       PetscCall(ISDestroy(&defcellIS));
5983       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5984       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5985       PetscCall(ISDestroy(&pointIS));
5986     }
5987     PetscCall(ISDestroy(&allcellIS));
5988 
5989     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5990     PetscCall(ISGetLocalSize(defcellIS, &n));
5991     PetscCall(ISGetIndices(defcellIS, &cells));
5992     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5993     PetscCall(ISRestoreIndices(defcellIS, &cells));
5994     PetscCall(ISDestroy(&defcellIS));
5995     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5996 
5997     PetscCall(PetscMalloc1(Ndef, &fields));
5998     for (f = 0; f < Nf; ++f)
5999       if (!dm->fields[f].label) fields[nf++] = f;
6000     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
6001     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
6002     PetscCall(ISSetType(fieldIS, ISGENERAL));
6003     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
6004 
6005     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
6006     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
6007     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
6008     PetscCall(DMLabelDestroy(&cellLabel));
6009     PetscCall(PetscDSDestroy(&dsDef));
6010     PetscCall(ISDestroy(&fieldIS));
6011     PetscCall(DMDestroy(&plex));
6012   }
6013   /* Create label DSes
6014      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
6015   */
6016   /* TODO Should check that labels are disjoint */
6017   for (l = 0; l < Nl; ++l) {
6018     DMLabel   label = labelSet[l];
6019     PetscDS   ds, dsIn = NULL;
6020     IS        fields;
6021     PetscInt *fld, nf;
6022 
6023     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
6024     for (f = 0, nf = 0; f < Nf; ++f)
6025       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
6026     PetscCall(PetscMalloc1(nf, &fld));
6027     for (f = 0, nf = 0; f < Nf; ++f)
6028       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
6029     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
6030     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
6031     PetscCall(ISSetType(fields, ISGENERAL));
6032     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
6033     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
6034     {
6035       DMPolytopeType ct;
6036       PetscInt       lStart, lEnd;
6037       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
6038 
6039       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
6040       if (lStart >= 0) {
6041         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
6042         switch (ct) {
6043         case DM_POLYTOPE_POINT_PRISM_TENSOR:
6044         case DM_POLYTOPE_SEG_PRISM_TENSOR:
6045         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6046         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
6047           isCohesiveLocal = PETSC_TRUE;
6048           break;
6049         default:
6050           break;
6051         }
6052       }
6053       PetscCallMPI(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
6054       if (isCohesive) {
6055         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
6056         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
6057       }
6058       for (f = 0, nf = 0; f < Nf; ++f) {
6059         if (label == dm->fields[f].label || !dm->fields[f].label) {
6060           if (label == dm->fields[f].label) {
6061             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
6062             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
6063             if (dsIn) {
6064               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
6065               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
6066             }
6067           }
6068           ++nf;
6069         }
6070       }
6071     }
6072     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
6073     PetscCall(ISDestroy(&fields));
6074     PetscCall(PetscDSDestroy(&ds));
6075     PetscCall(PetscDSDestroy(&dsIn));
6076   }
6077   PetscCall(PetscFree(labelSet));
6078   /* Set fields in DSes */
6079   for (s = 0; s < dm->Nds; ++s) {
6080     PetscDS         ds     = dm->probs[s].ds;
6081     PetscDS         dsIn   = dm->probs[s].dsIn;
6082     IS              fields = dm->probs[s].fields;
6083     const PetscInt *fld;
6084     PetscInt        nf, dsnf;
6085     PetscBool       isCohesive;
6086 
6087     PetscCall(PetscDSGetNumFields(ds, &dsnf));
6088     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
6089     PetscCall(ISGetLocalSize(fields, &nf));
6090     PetscCall(ISGetIndices(fields, &fld));
6091     for (f = 0; f < nf; ++f) {
6092       PetscObject  disc = dm->fields[fld[f]].disc;
6093       PetscBool    isCohesiveField;
6094       PetscClassId id;
6095 
6096       /* Handle DS with no fields */
6097       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
6098       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
6099       if (isCohesive) {
6100         if (!isCohesiveField) {
6101           PetscObject bdDisc;
6102 
6103           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
6104           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
6105           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6106         } else {
6107           PetscCall(PetscDSSetDiscretization(ds, f, disc));
6108           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6109         }
6110       } else {
6111         PetscCall(PetscDSSetDiscretization(ds, f, disc));
6112       }
6113       /* We allow people to have placeholder fields and construct the Section by hand */
6114       PetscCall(PetscObjectGetClassId(disc, &id));
6115       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
6116     }
6117     PetscCall(ISRestoreIndices(fields, &fld));
6118   }
6119   /* Allow k-jet tabulation */
6120   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6121   if (flg) {
6122     for (s = 0; s < dm->Nds; ++s) {
6123       PetscDS  ds   = dm->probs[s].ds;
6124       PetscDS  dsIn = dm->probs[s].dsIn;
6125       PetscInt Nf, f;
6126 
6127       PetscCall(PetscDSGetNumFields(ds, &Nf));
6128       for (f = 0; f < Nf; ++f) {
6129         PetscCall(PetscDSSetJetDegree(ds, f, k));
6130         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6131       }
6132     }
6133   }
6134   /* Setup DSes */
6135   if (doSetup) {
6136     for (s = 0; s < dm->Nds; ++s) {
6137       if (dm->setfromoptionscalled) {
6138         PetscCall(PetscDSSetFromOptions(dm->probs[s].ds));
6139         if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn));
6140       }
6141       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6142       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6143     }
6144   }
6145   PetscFunctionReturn(PETSC_SUCCESS);
6146 }
6147 
6148 /*@
6149   DMUseTensorOrder - Use a tensor product closure ordering for the default section
6150 
6151   Input Parameters:
6152 + dm     - The DM
6153 - tensor - Flag for tensor order
6154 
6155   Level: developer
6156 
6157 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()`
6158 @*/
6159 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor)
6160 {
6161   PetscInt  Nf;
6162   PetscBool reorder = PETSC_TRUE, isPlex;
6163 
6164   PetscFunctionBegin;
6165   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
6166   PetscCall(DMGetNumFields(dm, &Nf));
6167   for (PetscInt f = 0; f < Nf; ++f) {
6168     PetscObject  obj;
6169     PetscClassId id;
6170 
6171     PetscCall(DMGetField(dm, f, NULL, &obj));
6172     PetscCall(PetscObjectGetClassId(obj, &id));
6173     if (id == PETSCFE_CLASSID) {
6174       PetscSpace sp;
6175       PetscBool  tensor;
6176 
6177       PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp));
6178       PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor));
6179       reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE;
6180     } else reorder = PETSC_FALSE;
6181   }
6182   if (tensor) {
6183     if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
6184   } else {
6185     PetscSection s;
6186 
6187     PetscCall(DMGetLocalSection(dm, &s));
6188     if (s) PetscCall(PetscSectionResetClosurePermutation(s));
6189   }
6190   PetscFunctionReturn(PETSC_SUCCESS);
6191 }
6192 
6193 /*@
6194   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6195 
6196   Collective
6197 
6198   Input Parameters:
6199 + dm   - The `DM`
6200 - time - The time
6201 
6202   Output Parameters:
6203 + u   - The vector will be filled with exact solution values, or `NULL`
6204 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6205 
6206   Level: developer
6207 
6208   Note:
6209   The user must call `PetscDSSetExactSolution()` before using this routine
6210 
6211 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6212 @*/
6213 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6214 {
6215   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6216   void   **ectxs;
6217   Vec      locu, locu_t;
6218   PetscInt Nf, Nds, s;
6219 
6220   PetscFunctionBegin;
6221   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6222   if (u) {
6223     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6224     PetscCall(DMGetLocalVector(dm, &locu));
6225     PetscCall(VecSet(locu, 0.));
6226   }
6227   if (u_t) {
6228     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6229     PetscCall(DMGetLocalVector(dm, &locu_t));
6230     PetscCall(VecSet(locu_t, 0.));
6231   }
6232   PetscCall(DMGetNumFields(dm, &Nf));
6233   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6234   PetscCall(DMGetNumDS(dm, &Nds));
6235   for (s = 0; s < Nds; ++s) {
6236     PetscDS         ds;
6237     DMLabel         label;
6238     IS              fieldIS;
6239     const PetscInt *fields, id = 1;
6240     PetscInt        dsNf, f;
6241 
6242     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6243     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6244     PetscCall(ISGetIndices(fieldIS, &fields));
6245     PetscCall(PetscArrayzero(exacts, Nf));
6246     PetscCall(PetscArrayzero(ectxs, Nf));
6247     if (u) {
6248       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6249       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6250       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6251     }
6252     if (u_t) {
6253       PetscCall(PetscArrayzero(exacts, Nf));
6254       PetscCall(PetscArrayzero(ectxs, Nf));
6255       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6256       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6257       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6258     }
6259     PetscCall(ISRestoreIndices(fieldIS, &fields));
6260   }
6261   if (u) {
6262     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6263     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6264   }
6265   if (u_t) {
6266     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6267     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6268   }
6269   PetscCall(PetscFree2(exacts, ectxs));
6270   if (u) {
6271     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6272     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6273     PetscCall(DMRestoreLocalVector(dm, &locu));
6274   }
6275   if (u_t) {
6276     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6277     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6278     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6279   }
6280   PetscFunctionReturn(PETSC_SUCCESS);
6281 }
6282 
6283 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscInt minDegree, PetscInt maxDegree, PetscDS ds, PetscDS dsIn)
6284 {
6285   PetscDS dsNew, dsInNew = NULL;
6286 
6287   PetscFunctionBegin;
6288   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6289   PetscCall(PetscDSCopy(ds, minDegree, maxDegree, dm, dsNew));
6290   if (dsIn) {
6291     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6292     PetscCall(PetscDSCopy(dsIn, minDegree, maxDegree, dm, dsInNew));
6293   }
6294   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6295   PetscCall(PetscDSDestroy(&dsNew));
6296   PetscCall(PetscDSDestroy(&dsInNew));
6297   PetscFunctionReturn(PETSC_SUCCESS);
6298 }
6299 
6300 /*@
6301   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6302 
6303   Collective
6304 
6305   Input Parameters:
6306 + dm        - The `DM`
6307 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
6308 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
6309 
6310   Output Parameter:
6311 . newdm - The `DM`
6312 
6313   Level: advanced
6314 
6315 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6316 @*/
6317 PetscErrorCode DMCopyDS(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
6318 {
6319   PetscInt Nds, s;
6320 
6321   PetscFunctionBegin;
6322   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6323   PetscCall(DMGetNumDS(dm, &Nds));
6324   PetscCall(DMClearDS(newdm));
6325   for (s = 0; s < Nds; ++s) {
6326     DMLabel  label;
6327     IS       fields;
6328     PetscDS  ds, dsIn, newds;
6329     PetscInt Nbd, bd;
6330 
6331     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6332     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6333     PetscCall(DMTransferDS_Internal(newdm, label, fields, minDegree, maxDegree, ds, dsIn));
6334     /* Complete new labels in the new DS */
6335     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6336     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6337     for (bd = 0; bd < Nbd; ++bd) {
6338       PetscWeakForm wf;
6339       DMLabel       label;
6340       PetscInt      field;
6341 
6342       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6343       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6344     }
6345   }
6346   PetscCall(DMCompleteBCLabels_Internal(newdm));
6347   PetscFunctionReturn(PETSC_SUCCESS);
6348 }
6349 
6350 /*@
6351   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6352 
6353   Collective
6354 
6355   Input Parameter:
6356 . dm - The `DM`
6357 
6358   Output Parameter:
6359 . newdm - The `DM`
6360 
6361   Level: advanced
6362 
6363   Developer Note:
6364   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6365 
6366 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6367 @*/
6368 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6369 {
6370   PetscFunctionBegin;
6371   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6372   PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6373   PetscFunctionReturn(PETSC_SUCCESS);
6374 }
6375 
6376 /*@
6377   DMGetDimension - Return the topological dimension of the `DM`
6378 
6379   Not Collective
6380 
6381   Input Parameter:
6382 . dm - The `DM`
6383 
6384   Output Parameter:
6385 . dim - The topological dimension
6386 
6387   Level: beginner
6388 
6389 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6390 @*/
6391 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6392 {
6393   PetscFunctionBegin;
6394   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6395   PetscAssertPointer(dim, 2);
6396   *dim = dm->dim;
6397   PetscFunctionReturn(PETSC_SUCCESS);
6398 }
6399 
6400 /*@
6401   DMSetDimension - Set the topological dimension of the `DM`
6402 
6403   Collective
6404 
6405   Input Parameters:
6406 + dm  - The `DM`
6407 - dim - The topological dimension
6408 
6409   Level: beginner
6410 
6411 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6412 @*/
6413 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6414 {
6415   PetscDS  ds;
6416   PetscInt Nds, n;
6417 
6418   PetscFunctionBegin;
6419   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6420   PetscValidLogicalCollectiveInt(dm, dim, 2);
6421   dm->dim = dim;
6422   if (dm->dim >= 0) {
6423     PetscCall(DMGetNumDS(dm, &Nds));
6424     for (n = 0; n < Nds; ++n) {
6425       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6426       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6427     }
6428   }
6429   PetscFunctionReturn(PETSC_SUCCESS);
6430 }
6431 
6432 /*@
6433   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6434 
6435   Collective
6436 
6437   Input Parameters:
6438 + dm  - the `DM`
6439 - dim - the dimension
6440 
6441   Output Parameters:
6442 + pStart - The first point of the given dimension
6443 - pEnd   - The first point following points of the given dimension
6444 
6445   Level: intermediate
6446 
6447   Note:
6448   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6449   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6450   then the interval is empty.
6451 
6452 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6453 @*/
6454 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6455 {
6456   PetscInt d;
6457 
6458   PetscFunctionBegin;
6459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6460   PetscCall(DMGetDimension(dm, &d));
6461   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6462   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6463   PetscFunctionReturn(PETSC_SUCCESS);
6464 }
6465 
6466 /*@
6467   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6468 
6469   Collective
6470 
6471   Input Parameter:
6472 . dm - The original `DM`
6473 
6474   Output Parameter:
6475 . odm - The `DM` which provides the layout for output
6476 
6477   Level: intermediate
6478 
6479   Note:
6480   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6481   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6482   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6483 
6484 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6485 @*/
6486 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6487 {
6488   PetscSection section;
6489   IS           perm;
6490   PetscBool    hasConstraints, newDM, gnewDM;
6491 
6492   PetscFunctionBegin;
6493   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6494   PetscAssertPointer(odm, 2);
6495   PetscCall(DMGetLocalSection(dm, &section));
6496   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6497   PetscCall(PetscSectionGetPermutation(section, &perm));
6498   newDM = hasConstraints || perm ? PETSC_TRUE : PETSC_FALSE;
6499   PetscCallMPI(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6500   if (!gnewDM) {
6501     *odm = dm;
6502     PetscFunctionReturn(PETSC_SUCCESS);
6503   }
6504   if (!dm->dmBC) {
6505     PetscSection newSection, gsection;
6506     PetscSF      sf;
6507     PetscBool    usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE;
6508 
6509     PetscCall(DMClone(dm, &dm->dmBC));
6510     PetscCall(DMCopyDisc(dm, dm->dmBC));
6511     PetscCall(PetscSectionClone(section, &newSection));
6512     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6513     PetscCall(PetscSectionDestroy(&newSection));
6514     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6515     PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection));
6516     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6517     PetscCall(PetscSectionDestroy(&gsection));
6518   }
6519   *odm = dm->dmBC;
6520   PetscFunctionReturn(PETSC_SUCCESS);
6521 }
6522 
6523 /*@
6524   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6525 
6526   Input Parameter:
6527 . dm - The original `DM`
6528 
6529   Output Parameters:
6530 + num - The output sequence number
6531 - val - The output sequence value
6532 
6533   Level: intermediate
6534 
6535   Note:
6536   This is intended for output that should appear in sequence, for instance
6537   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6538 
6539   Developer Note:
6540   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6541   not directly related to the `DM`.
6542 
6543 .seealso: [](ch_dmbase), `DM`, `VecView()`
6544 @*/
6545 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6546 {
6547   PetscFunctionBegin;
6548   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6549   if (num) {
6550     PetscAssertPointer(num, 2);
6551     *num = dm->outputSequenceNum;
6552   }
6553   if (val) {
6554     PetscAssertPointer(val, 3);
6555     *val = dm->outputSequenceVal;
6556   }
6557   PetscFunctionReturn(PETSC_SUCCESS);
6558 }
6559 
6560 /*@
6561   DMSetOutputSequenceNumber - Set the sequence number/value for output
6562 
6563   Input Parameters:
6564 + dm  - The original `DM`
6565 . num - The output sequence number
6566 - val - The output sequence value
6567 
6568   Level: intermediate
6569 
6570   Note:
6571   This is intended for output that should appear in sequence, for instance
6572   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6573 
6574 .seealso: [](ch_dmbase), `DM`, `VecView()`
6575 @*/
6576 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6577 {
6578   PetscFunctionBegin;
6579   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6580   dm->outputSequenceNum = num;
6581   dm->outputSequenceVal = val;
6582   PetscFunctionReturn(PETSC_SUCCESS);
6583 }
6584 
6585 /*@
6586   DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6587 
6588   Input Parameters:
6589 + dm     - The original `DM`
6590 . viewer - The `PetscViewer` to get it from
6591 . name   - The sequence name
6592 - num    - The output sequence number
6593 
6594   Output Parameter:
6595 . val - The output sequence value
6596 
6597   Level: intermediate
6598 
6599   Note:
6600   This is intended for output that should appear in sequence, for instance
6601   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6602 
6603   Developer Note:
6604   It is unclear at the user API level why a `DM` is needed as input
6605 
6606 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6607 @*/
6608 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val)
6609 {
6610   PetscBool ishdf5;
6611 
6612   PetscFunctionBegin;
6613   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6614   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6615   PetscAssertPointer(name, 3);
6616   PetscAssertPointer(val, 5);
6617   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6618   if (ishdf5) {
6619 #if defined(PETSC_HAVE_HDF5)
6620     PetscScalar value;
6621 
6622     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6623     *val = PetscRealPart(value);
6624 #endif
6625   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6626   PetscFunctionReturn(PETSC_SUCCESS);
6627 }
6628 
6629 /*@
6630   DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer`
6631 
6632   Input Parameters:
6633 + dm     - The original `DM`
6634 . viewer - The `PetscViewer` to get it from
6635 - name   - The sequence name
6636 
6637   Output Parameter:
6638 . len - The length of the output sequence
6639 
6640   Level: intermediate
6641 
6642   Note:
6643   This is intended for output that should appear in sequence, for instance
6644   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6645 
6646   Developer Note:
6647   It is unclear at the user API level why a `DM` is needed as input
6648 
6649 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6650 @*/
6651 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len)
6652 {
6653   PetscBool ishdf5;
6654 
6655   PetscFunctionBegin;
6656   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6657   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6658   PetscAssertPointer(name, 3);
6659   PetscAssertPointer(len, 4);
6660   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6661   if (ishdf5) {
6662 #if defined(PETSC_HAVE_HDF5)
6663     PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer));
6664 #endif
6665   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6666   PetscFunctionReturn(PETSC_SUCCESS);
6667 }
6668 
6669 /*@
6670   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6671 
6672   Not Collective
6673 
6674   Input Parameter:
6675 . dm - The `DM`
6676 
6677   Output Parameter:
6678 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6679 
6680   Level: beginner
6681 
6682 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6683 @*/
6684 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6685 {
6686   PetscFunctionBegin;
6687   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6688   PetscAssertPointer(useNatural, 2);
6689   *useNatural = dm->useNatural;
6690   PetscFunctionReturn(PETSC_SUCCESS);
6691 }
6692 
6693 /*@
6694   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6695 
6696   Collective
6697 
6698   Input Parameters:
6699 + dm         - The `DM`
6700 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6701 
6702   Level: beginner
6703 
6704   Note:
6705   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6706 
6707 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6708 @*/
6709 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6710 {
6711   PetscFunctionBegin;
6712   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6713   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6714   dm->useNatural = useNatural;
6715   PetscFunctionReturn(PETSC_SUCCESS);
6716 }
6717 
6718 /*@
6719   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6720 
6721   Not Collective
6722 
6723   Input Parameters:
6724 + dm   - The `DM` object
6725 - name - The label name
6726 
6727   Level: intermediate
6728 
6729 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6730 @*/
6731 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6732 {
6733   PetscBool flg;
6734   DMLabel   label;
6735 
6736   PetscFunctionBegin;
6737   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6738   PetscAssertPointer(name, 2);
6739   PetscCall(DMHasLabel(dm, name, &flg));
6740   if (!flg) {
6741     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6742     PetscCall(DMAddLabel(dm, label));
6743     PetscCall(DMLabelDestroy(&label));
6744   }
6745   PetscFunctionReturn(PETSC_SUCCESS);
6746 }
6747 
6748 /*@
6749   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6750 
6751   Not Collective
6752 
6753   Input Parameters:
6754 + dm   - The `DM` object
6755 . l    - The index for the label
6756 - name - The label name
6757 
6758   Level: intermediate
6759 
6760 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6761 @*/
6762 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6763 {
6764   DMLabelLink orig, prev = NULL;
6765   DMLabel     label;
6766   PetscInt    Nl, m;
6767   PetscBool   flg, match;
6768   const char *lname;
6769 
6770   PetscFunctionBegin;
6771   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6772   PetscAssertPointer(name, 3);
6773   PetscCall(DMHasLabel(dm, name, &flg));
6774   if (!flg) {
6775     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6776     PetscCall(DMAddLabel(dm, label));
6777     PetscCall(DMLabelDestroy(&label));
6778   }
6779   PetscCall(DMGetNumLabels(dm, &Nl));
6780   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6781   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6782     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6783     PetscCall(PetscStrcmp(name, lname, &match));
6784     if (match) break;
6785   }
6786   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6787   if (!m) dm->labels = orig->next;
6788   else prev->next = orig->next;
6789   if (!l) {
6790     orig->next = dm->labels;
6791     dm->labels = orig;
6792   } else {
6793     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next);
6794     orig->next = prev->next;
6795     prev->next = orig;
6796   }
6797   PetscFunctionReturn(PETSC_SUCCESS);
6798 }
6799 
6800 /*@
6801   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6802 
6803   Not Collective
6804 
6805   Input Parameters:
6806 + dm    - The `DM` object
6807 . name  - The label name
6808 - point - The mesh point
6809 
6810   Output Parameter:
6811 . value - The label value for this point, or -1 if the point is not in the label
6812 
6813   Level: beginner
6814 
6815 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6816 @*/
6817 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6818 {
6819   DMLabel label;
6820 
6821   PetscFunctionBegin;
6822   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6823   PetscAssertPointer(name, 2);
6824   PetscCall(DMGetLabel(dm, name, &label));
6825   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6826   PetscCall(DMLabelGetValue(label, point, value));
6827   PetscFunctionReturn(PETSC_SUCCESS);
6828 }
6829 
6830 /*@
6831   DMSetLabelValue - Add a point to a `DMLabel` with given value
6832 
6833   Not Collective
6834 
6835   Input Parameters:
6836 + dm    - The `DM` object
6837 . name  - The label name
6838 . point - The mesh point
6839 - value - The label value for this point
6840 
6841   Output Parameter:
6842 
6843   Level: beginner
6844 
6845 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6846 @*/
6847 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6848 {
6849   DMLabel label;
6850 
6851   PetscFunctionBegin;
6852   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6853   PetscAssertPointer(name, 2);
6854   PetscCall(DMGetLabel(dm, name, &label));
6855   if (!label) {
6856     PetscCall(DMCreateLabel(dm, name));
6857     PetscCall(DMGetLabel(dm, name, &label));
6858   }
6859   PetscCall(DMLabelSetValue(label, point, value));
6860   PetscFunctionReturn(PETSC_SUCCESS);
6861 }
6862 
6863 /*@
6864   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6865 
6866   Not Collective
6867 
6868   Input Parameters:
6869 + dm    - The `DM` object
6870 . name  - The label name
6871 . point - The mesh point
6872 - value - The label value for this point
6873 
6874   Level: beginner
6875 
6876 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6877 @*/
6878 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6879 {
6880   DMLabel label;
6881 
6882   PetscFunctionBegin;
6883   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6884   PetscAssertPointer(name, 2);
6885   PetscCall(DMGetLabel(dm, name, &label));
6886   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6887   PetscCall(DMLabelClearValue(label, point, value));
6888   PetscFunctionReturn(PETSC_SUCCESS);
6889 }
6890 
6891 /*@
6892   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6893 
6894   Not Collective
6895 
6896   Input Parameters:
6897 + dm   - The `DM` object
6898 - name - The label name
6899 
6900   Output Parameter:
6901 . size - The number of different integer ids, or 0 if the label does not exist
6902 
6903   Level: beginner
6904 
6905   Developer Note:
6906   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6907 
6908 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6909 @*/
6910 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6911 {
6912   DMLabel label;
6913 
6914   PetscFunctionBegin;
6915   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6916   PetscAssertPointer(name, 2);
6917   PetscAssertPointer(size, 3);
6918   PetscCall(DMGetLabel(dm, name, &label));
6919   *size = 0;
6920   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6921   PetscCall(DMLabelGetNumValues(label, size));
6922   PetscFunctionReturn(PETSC_SUCCESS);
6923 }
6924 
6925 /*@
6926   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6927 
6928   Not Collective
6929 
6930   Input Parameters:
6931 + dm   - The `DM` object
6932 - name - The label name
6933 
6934   Output Parameter:
6935 . ids - The integer ids, or `NULL` if the label does not exist
6936 
6937   Level: beginner
6938 
6939 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6940 @*/
6941 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6942 {
6943   DMLabel label;
6944 
6945   PetscFunctionBegin;
6946   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6947   PetscAssertPointer(name, 2);
6948   PetscAssertPointer(ids, 3);
6949   PetscCall(DMGetLabel(dm, name, &label));
6950   *ids = NULL;
6951   if (label) {
6952     PetscCall(DMLabelGetValueIS(label, ids));
6953   } else {
6954     /* returning an empty IS */
6955     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6956   }
6957   PetscFunctionReturn(PETSC_SUCCESS);
6958 }
6959 
6960 /*@
6961   DMGetStratumSize - Get the number of points in a label stratum
6962 
6963   Not Collective
6964 
6965   Input Parameters:
6966 + dm    - The `DM` object
6967 . name  - The label name of the stratum
6968 - value - The stratum value
6969 
6970   Output Parameter:
6971 . size - The number of points, also called the stratum size
6972 
6973   Level: beginner
6974 
6975 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6976 @*/
6977 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6978 {
6979   DMLabel label;
6980 
6981   PetscFunctionBegin;
6982   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6983   PetscAssertPointer(name, 2);
6984   PetscAssertPointer(size, 4);
6985   PetscCall(DMGetLabel(dm, name, &label));
6986   *size = 0;
6987   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6988   PetscCall(DMLabelGetStratumSize(label, value, size));
6989   PetscFunctionReturn(PETSC_SUCCESS);
6990 }
6991 
6992 /*@
6993   DMGetStratumIS - Get the points in a label stratum
6994 
6995   Not Collective
6996 
6997   Input Parameters:
6998 + dm    - The `DM` object
6999 . name  - The label name
7000 - value - The stratum value
7001 
7002   Output Parameter:
7003 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
7004 
7005   Level: beginner
7006 
7007 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
7008 @*/
7009 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7010 {
7011   DMLabel label;
7012 
7013   PetscFunctionBegin;
7014   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7015   PetscAssertPointer(name, 2);
7016   PetscAssertPointer(points, 4);
7017   PetscCall(DMGetLabel(dm, name, &label));
7018   *points = NULL;
7019   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7020   PetscCall(DMLabelGetStratumIS(label, value, points));
7021   PetscFunctionReturn(PETSC_SUCCESS);
7022 }
7023 
7024 /*@
7025   DMSetStratumIS - Set the points in a label stratum
7026 
7027   Not Collective
7028 
7029   Input Parameters:
7030 + dm     - The `DM` object
7031 . name   - The label name
7032 . value  - The stratum value
7033 - points - The stratum points
7034 
7035   Level: beginner
7036 
7037 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
7038 @*/
7039 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7040 {
7041   DMLabel label;
7042 
7043   PetscFunctionBegin;
7044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7045   PetscAssertPointer(name, 2);
7046   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
7047   PetscCall(DMGetLabel(dm, name, &label));
7048   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7049   PetscCall(DMLabelSetStratumIS(label, value, points));
7050   PetscFunctionReturn(PETSC_SUCCESS);
7051 }
7052 
7053 /*@
7054   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
7055 
7056   Not Collective
7057 
7058   Input Parameters:
7059 + dm    - The `DM` object
7060 . name  - The label name
7061 - value - The label value for this point
7062 
7063   Output Parameter:
7064 
7065   Level: beginner
7066 
7067 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7068 @*/
7069 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7070 {
7071   DMLabel label;
7072 
7073   PetscFunctionBegin;
7074   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7075   PetscAssertPointer(name, 2);
7076   PetscCall(DMGetLabel(dm, name, &label));
7077   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7078   PetscCall(DMLabelClearStratum(label, value));
7079   PetscFunctionReturn(PETSC_SUCCESS);
7080 }
7081 
7082 /*@
7083   DMGetNumLabels - Return the number of labels defined by on the `DM`
7084 
7085   Not Collective
7086 
7087   Input Parameter:
7088 . dm - The `DM` object
7089 
7090   Output Parameter:
7091 . numLabels - the number of Labels
7092 
7093   Level: intermediate
7094 
7095 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7096 @*/
7097 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7098 {
7099   DMLabelLink next = dm->labels;
7100   PetscInt    n    = 0;
7101 
7102   PetscFunctionBegin;
7103   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7104   PetscAssertPointer(numLabels, 2);
7105   while (next) {
7106     ++n;
7107     next = next->next;
7108   }
7109   *numLabels = n;
7110   PetscFunctionReturn(PETSC_SUCCESS);
7111 }
7112 
7113 /*@
7114   DMGetLabelName - Return the name of nth label
7115 
7116   Not Collective
7117 
7118   Input Parameters:
7119 + dm - The `DM` object
7120 - n  - the label number
7121 
7122   Output Parameter:
7123 . name - the label name
7124 
7125   Level: intermediate
7126 
7127   Developer Note:
7128   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
7129 
7130 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7131 @*/
7132 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[])
7133 {
7134   DMLabelLink next = dm->labels;
7135   PetscInt    l    = 0;
7136 
7137   PetscFunctionBegin;
7138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7139   PetscAssertPointer(name, 3);
7140   while (next) {
7141     if (l == n) {
7142       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
7143       PetscFunctionReturn(PETSC_SUCCESS);
7144     }
7145     ++l;
7146     next = next->next;
7147   }
7148   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7149 }
7150 
7151 /*@
7152   DMHasLabel - Determine whether the `DM` has a label of a given name
7153 
7154   Not Collective
7155 
7156   Input Parameters:
7157 + dm   - The `DM` object
7158 - name - The label name
7159 
7160   Output Parameter:
7161 . hasLabel - `PETSC_TRUE` if the label is present
7162 
7163   Level: intermediate
7164 
7165 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7166 @*/
7167 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7168 {
7169   DMLabelLink next = dm->labels;
7170   const char *lname;
7171 
7172   PetscFunctionBegin;
7173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7174   PetscAssertPointer(name, 2);
7175   PetscAssertPointer(hasLabel, 3);
7176   *hasLabel = PETSC_FALSE;
7177   while (next) {
7178     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7179     PetscCall(PetscStrcmp(name, lname, hasLabel));
7180     if (*hasLabel) break;
7181     next = next->next;
7182   }
7183   PetscFunctionReturn(PETSC_SUCCESS);
7184 }
7185 
7186 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7187 /*@
7188   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
7189 
7190   Not Collective
7191 
7192   Input Parameters:
7193 + dm   - The `DM` object
7194 - name - The label name
7195 
7196   Output Parameter:
7197 . label - The `DMLabel`, or `NULL` if the label is absent
7198 
7199   Default labels in a `DMPLEX`:
7200 + "depth"       - Holds the depth (co-dimension) of each mesh point
7201 . "celltype"    - Holds the topological type of each cell
7202 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7203 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7204 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7205 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7206 
7207   Level: intermediate
7208 
7209 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7210 @*/
7211 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7212 {
7213   DMLabelLink next = dm->labels;
7214   PetscBool   hasLabel;
7215   const char *lname;
7216 
7217   PetscFunctionBegin;
7218   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7219   PetscAssertPointer(name, 2);
7220   PetscAssertPointer(label, 3);
7221   *label = NULL;
7222   while (next) {
7223     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7224     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7225     if (hasLabel) {
7226       *label = next->label;
7227       break;
7228     }
7229     next = next->next;
7230   }
7231   PetscFunctionReturn(PETSC_SUCCESS);
7232 }
7233 
7234 /*@
7235   DMGetLabelByNum - Return the nth label on a `DM`
7236 
7237   Not Collective
7238 
7239   Input Parameters:
7240 + dm - The `DM` object
7241 - n  - the label number
7242 
7243   Output Parameter:
7244 . label - the label
7245 
7246   Level: intermediate
7247 
7248 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7249 @*/
7250 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7251 {
7252   DMLabelLink next = dm->labels;
7253   PetscInt    l    = 0;
7254 
7255   PetscFunctionBegin;
7256   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7257   PetscAssertPointer(label, 3);
7258   while (next) {
7259     if (l == n) {
7260       *label = next->label;
7261       PetscFunctionReturn(PETSC_SUCCESS);
7262     }
7263     ++l;
7264     next = next->next;
7265   }
7266   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7267 }
7268 
7269 /*@
7270   DMAddLabel - Add the label to this `DM`
7271 
7272   Not Collective
7273 
7274   Input Parameters:
7275 + dm    - The `DM` object
7276 - label - The `DMLabel`
7277 
7278   Level: developer
7279 
7280 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7281 @*/
7282 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7283 {
7284   DMLabelLink l, *p, tmpLabel;
7285   PetscBool   hasLabel;
7286   const char *lname;
7287   PetscBool   flg;
7288 
7289   PetscFunctionBegin;
7290   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7291   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7292   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7293   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7294   PetscCall(PetscCalloc1(1, &tmpLabel));
7295   tmpLabel->label  = label;
7296   tmpLabel->output = PETSC_TRUE;
7297   for (p = &dm->labels; (l = *p); p = &l->next) { }
7298   *p = tmpLabel;
7299   PetscCall(PetscObjectReference((PetscObject)label));
7300   PetscCall(PetscStrcmp(lname, "depth", &flg));
7301   if (flg) dm->depthLabel = label;
7302   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7303   if (flg) dm->celltypeLabel = label;
7304   PetscFunctionReturn(PETSC_SUCCESS);
7305 }
7306 
7307 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7308 /*@
7309   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7310 
7311   Not Collective
7312 
7313   Input Parameters:
7314 + dm    - The `DM` object
7315 - label - The `DMLabel`, having the same name, to substitute
7316 
7317   Default labels in a `DMPLEX`:
7318 + "depth"       - Holds the depth (co-dimension) of each mesh point
7319 . "celltype"    - Holds the topological type of each cell
7320 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7321 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7322 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7323 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7324 
7325   Level: intermediate
7326 
7327 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7328 @*/
7329 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7330 {
7331   DMLabelLink next = dm->labels;
7332   PetscBool   hasLabel, flg;
7333   const char *name, *lname;
7334 
7335   PetscFunctionBegin;
7336   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7337   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7338   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7339   while (next) {
7340     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7341     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7342     if (hasLabel) {
7343       PetscCall(PetscObjectReference((PetscObject)label));
7344       PetscCall(PetscStrcmp(lname, "depth", &flg));
7345       if (flg) dm->depthLabel = label;
7346       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7347       if (flg) dm->celltypeLabel = label;
7348       PetscCall(DMLabelDestroy(&next->label));
7349       next->label = label;
7350       break;
7351     }
7352     next = next->next;
7353   }
7354   PetscFunctionReturn(PETSC_SUCCESS);
7355 }
7356 
7357 /*@
7358   DMRemoveLabel - Remove the label given by name from this `DM`
7359 
7360   Not Collective
7361 
7362   Input Parameters:
7363 + dm   - The `DM` object
7364 - name - The label name
7365 
7366   Output Parameter:
7367 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7368           caller is responsible for calling `DMLabelDestroy()`.
7369 
7370   Level: developer
7371 
7372 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7373 @*/
7374 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7375 {
7376   DMLabelLink link, *pnext;
7377   PetscBool   hasLabel;
7378   const char *lname;
7379 
7380   PetscFunctionBegin;
7381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7382   PetscAssertPointer(name, 2);
7383   if (label) {
7384     PetscAssertPointer(label, 3);
7385     *label = NULL;
7386   }
7387   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7388     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7389     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7390     if (hasLabel) {
7391       *pnext = link->next; /* Remove from list */
7392       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7393       if (hasLabel) dm->depthLabel = NULL;
7394       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7395       if (hasLabel) dm->celltypeLabel = NULL;
7396       if (label) *label = link->label;
7397       else PetscCall(DMLabelDestroy(&link->label));
7398       PetscCall(PetscFree(link));
7399       break;
7400     }
7401   }
7402   PetscFunctionReturn(PETSC_SUCCESS);
7403 }
7404 
7405 /*@
7406   DMRemoveLabelBySelf - Remove the label from this `DM`
7407 
7408   Not Collective
7409 
7410   Input Parameters:
7411 + dm           - The `DM` object
7412 . label        - The `DMLabel` to be removed from the `DM`
7413 - failNotFound - Should it fail if the label is not found in the `DM`?
7414 
7415   Level: developer
7416 
7417   Note:
7418   Only exactly the same instance is removed if found, name match is ignored.
7419   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7420   *label nullified.
7421 
7422 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7423 @*/
7424 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7425 {
7426   DMLabelLink link, *pnext;
7427   PetscBool   hasLabel = PETSC_FALSE;
7428 
7429   PetscFunctionBegin;
7430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7431   PetscAssertPointer(label, 2);
7432   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7433   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7434   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7435   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7436     if (*label == link->label) {
7437       hasLabel = PETSC_TRUE;
7438       *pnext   = link->next; /* Remove from list */
7439       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7440       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7441       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7442       PetscCall(DMLabelDestroy(&link->label));
7443       PetscCall(PetscFree(link));
7444       break;
7445     }
7446   }
7447   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7448   PetscFunctionReturn(PETSC_SUCCESS);
7449 }
7450 
7451 /*@
7452   DMGetLabelOutput - Get the output flag for a given label
7453 
7454   Not Collective
7455 
7456   Input Parameters:
7457 + dm   - The `DM` object
7458 - name - The label name
7459 
7460   Output Parameter:
7461 . output - The flag for output
7462 
7463   Level: developer
7464 
7465 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7466 @*/
7467 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7468 {
7469   DMLabelLink next = dm->labels;
7470   const char *lname;
7471 
7472   PetscFunctionBegin;
7473   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7474   PetscAssertPointer(name, 2);
7475   PetscAssertPointer(output, 3);
7476   while (next) {
7477     PetscBool flg;
7478 
7479     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7480     PetscCall(PetscStrcmp(name, lname, &flg));
7481     if (flg) {
7482       *output = next->output;
7483       PetscFunctionReturn(PETSC_SUCCESS);
7484     }
7485     next = next->next;
7486   }
7487   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7488 }
7489 
7490 /*@
7491   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7492 
7493   Not Collective
7494 
7495   Input Parameters:
7496 + dm     - The `DM` object
7497 . name   - The label name
7498 - output - `PETSC_TRUE` to save the label to the viewer
7499 
7500   Level: developer
7501 
7502 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7503 @*/
7504 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7505 {
7506   DMLabelLink next = dm->labels;
7507   const char *lname;
7508 
7509   PetscFunctionBegin;
7510   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7511   PetscAssertPointer(name, 2);
7512   while (next) {
7513     PetscBool flg;
7514 
7515     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7516     PetscCall(PetscStrcmp(name, lname, &flg));
7517     if (flg) {
7518       next->output = output;
7519       PetscFunctionReturn(PETSC_SUCCESS);
7520     }
7521     next = next->next;
7522   }
7523   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7524 }
7525 
7526 /*@
7527   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7528 
7529   Collective
7530 
7531   Input Parameters:
7532 + dmA   - The `DM` object with initial labels
7533 . dmB   - The `DM` object to which labels are copied
7534 . mode  - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7535 . all   - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7536 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7537 
7538   Level: intermediate
7539 
7540   Note:
7541   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7542 
7543 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7544 @*/
7545 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7546 {
7547   DMLabel     label, labelNew, labelOld;
7548   const char *name;
7549   PetscBool   flg;
7550   DMLabelLink link;
7551 
7552   PetscFunctionBegin;
7553   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7554   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7555   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7556   PetscValidLogicalCollectiveBool(dmA, all, 4);
7557   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7558   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7559   for (link = dmA->labels; link; link = link->next) {
7560     label = link->label;
7561     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7562     if (!all) {
7563       PetscCall(PetscStrcmp(name, "depth", &flg));
7564       if (flg) continue;
7565       PetscCall(PetscStrcmp(name, "dim", &flg));
7566       if (flg) continue;
7567       PetscCall(PetscStrcmp(name, "celltype", &flg));
7568       if (flg) continue;
7569     }
7570     PetscCall(DMGetLabel(dmB, name, &labelOld));
7571     if (labelOld) {
7572       switch (emode) {
7573       case DM_COPY_LABELS_KEEP:
7574         continue;
7575       case DM_COPY_LABELS_REPLACE:
7576         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7577         break;
7578       case DM_COPY_LABELS_FAIL:
7579         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7580       default:
7581         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7582       }
7583     }
7584     if (mode == PETSC_COPY_VALUES) {
7585       PetscCall(DMLabelDuplicate(label, &labelNew));
7586     } else {
7587       labelNew = label;
7588     }
7589     PetscCall(DMAddLabel(dmB, labelNew));
7590     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7591   }
7592   PetscFunctionReturn(PETSC_SUCCESS);
7593 }
7594 
7595 /*@C
7596   DMCompareLabels - Compare labels between two `DM` objects
7597 
7598   Collective; No Fortran Support
7599 
7600   Input Parameters:
7601 + dm0 - First `DM` object
7602 - dm1 - Second `DM` object
7603 
7604   Output Parameters:
7605 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7606 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7607 
7608   Level: intermediate
7609 
7610   Notes:
7611   The output flag equal will be the same on all processes.
7612 
7613   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7614 
7615   Make sure to pass equal is `NULL` on all processes or none of them.
7616 
7617   The output message is set independently on each rank.
7618 
7619   message must be freed with `PetscFree()`
7620 
7621   If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner.
7622 
7623   Make sure to pass message as `NULL` on all processes or no processes.
7624 
7625   Labels are matched by name. If the number of labels and their names are equal,
7626   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7627 
7628   Developer Note:
7629   Can automatically generate the Fortran stub because `message` must be freed with `PetscFree()`
7630 
7631 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7632 @*/
7633 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7634 {
7635   PetscInt    n, i;
7636   char        msg[PETSC_MAX_PATH_LEN] = "";
7637   PetscBool   eq;
7638   MPI_Comm    comm;
7639   PetscMPIInt rank;
7640 
7641   PetscFunctionBegin;
7642   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7643   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7644   PetscCheckSameComm(dm0, 1, dm1, 2);
7645   if (equal) PetscAssertPointer(equal, 3);
7646   if (message) PetscAssertPointer(message, 4);
7647   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7648   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7649   {
7650     PetscInt n1;
7651 
7652     PetscCall(DMGetNumLabels(dm0, &n));
7653     PetscCall(DMGetNumLabels(dm1, &n1));
7654     eq = (PetscBool)(n == n1);
7655     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7656     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7657     if (!eq) goto finish;
7658   }
7659   for (i = 0; i < n; i++) {
7660     DMLabel     l0, l1;
7661     const char *name;
7662     char       *msgInner;
7663 
7664     /* Ignore label order */
7665     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7666     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7667     PetscCall(DMGetLabel(dm1, name, &l1));
7668     if (!l1) {
7669       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7670       eq = PETSC_FALSE;
7671       break;
7672     }
7673     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7674     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7675     PetscCall(PetscFree(msgInner));
7676     if (!eq) break;
7677   }
7678   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7679 finish:
7680   /* If message output arg not set, print to stderr */
7681   if (message) {
7682     *message = NULL;
7683     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7684   } else {
7685     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7686     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7687   }
7688   /* If same output arg not ser and labels are not equal, throw error */
7689   if (equal) *equal = eq;
7690   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7691   PetscFunctionReturn(PETSC_SUCCESS);
7692 }
7693 
7694 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7695 {
7696   PetscFunctionBegin;
7697   PetscAssertPointer(label, 2);
7698   if (!*label) {
7699     PetscCall(DMCreateLabel(dm, name));
7700     PetscCall(DMGetLabel(dm, name, label));
7701   }
7702   PetscCall(DMLabelSetValue(*label, point, value));
7703   PetscFunctionReturn(PETSC_SUCCESS);
7704 }
7705 
7706 /*
7707   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7708   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7709   (label, id) pair in the DM.
7710 
7711   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7712   each label.
7713 */
7714 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7715 {
7716   DMUniversalLabel ul;
7717   PetscBool       *active;
7718   PetscInt         pStart, pEnd, p, Nl, l, m;
7719 
7720   PetscFunctionBegin;
7721   PetscCall(PetscMalloc1(1, &ul));
7722   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7723   PetscCall(DMGetNumLabels(dm, &Nl));
7724   PetscCall(PetscCalloc1(Nl, &active));
7725   ul->Nl = 0;
7726   for (l = 0; l < Nl; ++l) {
7727     PetscBool   isdepth, iscelltype;
7728     const char *name;
7729 
7730     PetscCall(DMGetLabelName(dm, l, &name));
7731     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7732     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7733     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7734     if (active[l]) ++ul->Nl;
7735   }
7736   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7737   ul->Nv = 0;
7738   for (l = 0, m = 0; l < Nl; ++l) {
7739     DMLabel     label;
7740     PetscInt    nv;
7741     const char *name;
7742 
7743     if (!active[l]) continue;
7744     PetscCall(DMGetLabelName(dm, l, &name));
7745     PetscCall(DMGetLabelByNum(dm, l, &label));
7746     PetscCall(DMLabelGetNumValues(label, &nv));
7747     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7748     ul->indices[m] = l;
7749     ul->Nv += nv;
7750     ul->offsets[m + 1] = nv;
7751     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7752     ++m;
7753   }
7754   for (l = 1; l <= ul->Nl; ++l) {
7755     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7756     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7757   }
7758   for (l = 0; l < ul->Nl; ++l) {
7759     PetscInt b;
7760 
7761     ul->masks[l] = 0;
7762     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7763   }
7764   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7765   for (l = 0, m = 0; l < Nl; ++l) {
7766     DMLabel         label;
7767     IS              valueIS;
7768     const PetscInt *varr;
7769     PetscInt        nv, v;
7770 
7771     if (!active[l]) continue;
7772     PetscCall(DMGetLabelByNum(dm, l, &label));
7773     PetscCall(DMLabelGetNumValues(label, &nv));
7774     PetscCall(DMLabelGetValueIS(label, &valueIS));
7775     PetscCall(ISGetIndices(valueIS, &varr));
7776     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7777     PetscCall(ISRestoreIndices(valueIS, &varr));
7778     PetscCall(ISDestroy(&valueIS));
7779     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7780     ++m;
7781   }
7782   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7783   for (p = pStart; p < pEnd; ++p) {
7784     PetscInt  uval   = 0;
7785     PetscBool marked = PETSC_FALSE;
7786 
7787     for (l = 0, m = 0; l < Nl; ++l) {
7788       DMLabel  label;
7789       PetscInt val, defval, loc, nv;
7790 
7791       if (!active[l]) continue;
7792       PetscCall(DMGetLabelByNum(dm, l, &label));
7793       PetscCall(DMLabelGetValue(label, p, &val));
7794       PetscCall(DMLabelGetDefaultValue(label, &defval));
7795       if (val == defval) {
7796         ++m;
7797         continue;
7798       }
7799       nv     = ul->offsets[m + 1] - ul->offsets[m];
7800       marked = PETSC_TRUE;
7801       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7802       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7803       uval += (loc + 1) << ul->bits[m];
7804       ++m;
7805     }
7806     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7807   }
7808   PetscCall(PetscFree(active));
7809   *universal = ul;
7810   PetscFunctionReturn(PETSC_SUCCESS);
7811 }
7812 
7813 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7814 {
7815   PetscInt l;
7816 
7817   PetscFunctionBegin;
7818   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7819   PetscCall(DMLabelDestroy(&(*universal)->label));
7820   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7821   PetscCall(PetscFree((*universal)->values));
7822   PetscCall(PetscFree(*universal));
7823   *universal = NULL;
7824   PetscFunctionReturn(PETSC_SUCCESS);
7825 }
7826 
7827 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7828 {
7829   PetscFunctionBegin;
7830   PetscAssertPointer(ulabel, 2);
7831   *ulabel = ul->label;
7832   PetscFunctionReturn(PETSC_SUCCESS);
7833 }
7834 
7835 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7836 {
7837   PetscInt Nl = ul->Nl, l;
7838 
7839   PetscFunctionBegin;
7840   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7841   for (l = 0; l < Nl; ++l) {
7842     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7843     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7844   }
7845   if (preserveOrder) {
7846     for (l = 0; l < ul->Nl; ++l) {
7847       const char *name;
7848       PetscBool   match;
7849 
7850       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7851       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7852       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]);
7853     }
7854   }
7855   PetscFunctionReturn(PETSC_SUCCESS);
7856 }
7857 
7858 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7859 {
7860   PetscInt l;
7861 
7862   PetscFunctionBegin;
7863   for (l = 0; l < ul->Nl; ++l) {
7864     DMLabel  label;
7865     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7866 
7867     if (lval) {
7868       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7869       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7870       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7871     }
7872   }
7873   PetscFunctionReturn(PETSC_SUCCESS);
7874 }
7875 
7876 /*@
7877   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7878 
7879   Not Collective
7880 
7881   Input Parameter:
7882 . dm - The `DM` object
7883 
7884   Output Parameter:
7885 . cdm - The coarse `DM`
7886 
7887   Level: intermediate
7888 
7889 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7890 @*/
7891 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7892 {
7893   PetscFunctionBegin;
7894   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7895   PetscAssertPointer(cdm, 2);
7896   *cdm = dm->coarseMesh;
7897   PetscFunctionReturn(PETSC_SUCCESS);
7898 }
7899 
7900 /*@
7901   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7902 
7903   Input Parameters:
7904 + dm  - The `DM` object
7905 - cdm - The coarse `DM`
7906 
7907   Level: intermediate
7908 
7909   Note:
7910   Normally this is set automatically by `DMRefine()`
7911 
7912 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7913 @*/
7914 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7915 {
7916   PetscFunctionBegin;
7917   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7918   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7919   if (dm == cdm) cdm = NULL;
7920   PetscCall(PetscObjectReference((PetscObject)cdm));
7921   PetscCall(DMDestroy(&dm->coarseMesh));
7922   dm->coarseMesh = cdm;
7923   PetscFunctionReturn(PETSC_SUCCESS);
7924 }
7925 
7926 /*@
7927   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7928 
7929   Input Parameter:
7930 . dm - The `DM` object
7931 
7932   Output Parameter:
7933 . fdm - The fine `DM`
7934 
7935   Level: intermediate
7936 
7937 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7938 @*/
7939 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7940 {
7941   PetscFunctionBegin;
7942   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7943   PetscAssertPointer(fdm, 2);
7944   *fdm = dm->fineMesh;
7945   PetscFunctionReturn(PETSC_SUCCESS);
7946 }
7947 
7948 /*@
7949   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7950 
7951   Input Parameters:
7952 + dm  - The `DM` object
7953 - fdm - The fine `DM`
7954 
7955   Level: developer
7956 
7957   Note:
7958   Normally this is set automatically by `DMCoarsen()`
7959 
7960 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7961 @*/
7962 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7963 {
7964   PetscFunctionBegin;
7965   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7966   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7967   if (dm == fdm) fdm = NULL;
7968   PetscCall(PetscObjectReference((PetscObject)fdm));
7969   PetscCall(DMDestroy(&dm->fineMesh));
7970   dm->fineMesh = fdm;
7971   PetscFunctionReturn(PETSC_SUCCESS);
7972 }
7973 
7974 /*@C
7975   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7976 
7977   Collective
7978 
7979   Input Parameters:
7980 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7981 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7982 . name     - The BC name
7983 . label    - The label defining constrained points
7984 . Nv       - The number of `DMLabel` values for constrained points
7985 . values   - An array of values for constrained points
7986 . field    - The field to constrain
7987 . Nc       - The number of constrained field components (0 will constrain all fields)
7988 . comps    - An array of constrained component numbers
7989 . bcFunc   - A pointwise function giving boundary values
7990 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7991 - ctx      - An optional user context for bcFunc
7992 
7993   Output Parameter:
7994 . bd - (Optional) Boundary number
7995 
7996   Options Database Keys:
7997 + -bc_<boundary name> <num>      - Overrides the boundary ids
7998 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7999 
8000   Level: intermediate
8001 
8002   Notes:
8003   Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
8004 .vb
8005  void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8006 .ve
8007 
8008   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
8009 
8010 .vb
8011   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8012               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8013               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8014               PetscReal time, const PetscReal x[], PetscScalar bcval[])
8015 .ve
8016 + dim - the spatial dimension
8017 . Nf - the number of fields
8018 . uOff - the offset into u[] and u_t[] for each field
8019 . uOff_x - the offset into u_x[] for each field
8020 . u - each field evaluated at the current point
8021 . u_t - the time derivative of each field evaluated at the current point
8022 . u_x - the gradient of each field evaluated at the current point
8023 . aOff - the offset into a[] and a_t[] for each auxiliary field
8024 . aOff_x - the offset into a_x[] for each auxiliary field
8025 . a - each auxiliary field evaluated at the current point
8026 . a_t - the time derivative of each auxiliary field evaluated at the current point
8027 . a_x - the gradient of auxiliary each field evaluated at the current point
8028 . t - current time
8029 . x - coordinates of the current point
8030 . numConstants - number of constant parameters
8031 . constants - constant parameters
8032 - bcval - output values at the current point
8033 
8034 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
8035 @*/
8036 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)
8037 {
8038   PetscDS ds;
8039 
8040   PetscFunctionBegin;
8041   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8042   PetscValidLogicalCollectiveEnum(dm, type, 2);
8043   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8044   PetscValidLogicalCollectiveInt(dm, Nv, 5);
8045   PetscValidLogicalCollectiveInt(dm, field, 7);
8046   PetscValidLogicalCollectiveInt(dm, Nc, 8);
8047   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
8048   PetscCall(DMGetDS(dm, &ds));
8049   /* Complete label */
8050   if (label) {
8051     PetscObject  obj;
8052     PetscClassId id;
8053 
8054     PetscCall(DMGetField(dm, field, NULL, &obj));
8055     PetscCall(PetscObjectGetClassId(obj, &id));
8056     if (id == PETSCFE_CLASSID) {
8057       DM plex;
8058 
8059       PetscCall(DMConvert(dm, DMPLEX, &plex));
8060       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8061       PetscCall(DMDestroy(&plex));
8062     }
8063   }
8064   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8065   PetscFunctionReturn(PETSC_SUCCESS);
8066 }
8067 
8068 /* TODO Remove this since now the structures are the same */
8069 static PetscErrorCode DMPopulateBoundary(DM dm)
8070 {
8071   PetscDS     ds;
8072   DMBoundary *lastnext;
8073   DSBoundary  dsbound;
8074 
8075   PetscFunctionBegin;
8076   PetscCall(DMGetDS(dm, &ds));
8077   dsbound = ds->boundary;
8078   if (dm->boundary) {
8079     DMBoundary next = dm->boundary;
8080 
8081     /* quick check to see if the PetscDS has changed */
8082     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
8083     /* the PetscDS has changed: tear down and rebuild */
8084     while (next) {
8085       DMBoundary b = next;
8086 
8087       next = b->next;
8088       PetscCall(PetscFree(b));
8089     }
8090     dm->boundary = NULL;
8091   }
8092 
8093   lastnext = &dm->boundary;
8094   while (dsbound) {
8095     DMBoundary dmbound;
8096 
8097     PetscCall(PetscNew(&dmbound));
8098     dmbound->dsboundary = dsbound;
8099     dmbound->label      = dsbound->label;
8100     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8101     *lastnext = dmbound;
8102     lastnext  = &dmbound->next;
8103     dsbound   = dsbound->next;
8104   }
8105   PetscFunctionReturn(PETSC_SUCCESS);
8106 }
8107 
8108 /* TODO: missing manual page */
8109 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8110 {
8111   DMBoundary b;
8112 
8113   PetscFunctionBegin;
8114   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8115   PetscAssertPointer(isBd, 3);
8116   *isBd = PETSC_FALSE;
8117   PetscCall(DMPopulateBoundary(dm));
8118   b = dm->boundary;
8119   while (b && !*isBd) {
8120     DMLabel    label = b->label;
8121     DSBoundary dsb   = b->dsboundary;
8122     PetscInt   i;
8123 
8124     if (label) {
8125       for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8126     }
8127     b = b->next;
8128   }
8129   PetscFunctionReturn(PETSC_SUCCESS);
8130 }
8131 
8132 /*@C
8133   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
8134 
8135   Collective
8136 
8137   Input Parameters:
8138 + dm    - The `DM`
8139 . time  - The time
8140 . funcs - The coordinate functions to evaluate, one per field
8141 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8142 - mode  - The insertion mode for values
8143 
8144   Output Parameter:
8145 . X - vector
8146 
8147   Calling sequence of `funcs`:
8148 + dim  - The spatial dimension
8149 . time - The time at which to sample
8150 . x    - The coordinates
8151 . Nc   - The number of components
8152 . u    - The output field values
8153 - ctx  - optional user-defined function context
8154 
8155   Level: developer
8156 
8157   Developer Notes:
8158   This API is specific to only particular usage of `DM`
8159 
8160   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8161 
8162 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8163 @*/
8164 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)
8165 {
8166   Vec localX;
8167 
8168   PetscFunctionBegin;
8169   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8170   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
8171   PetscCall(DMGetLocalVector(dm, &localX));
8172   PetscCall(VecSet(localX, 0.));
8173   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8174   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8175   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8176   PetscCall(DMRestoreLocalVector(dm, &localX));
8177   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
8178   PetscFunctionReturn(PETSC_SUCCESS);
8179 }
8180 
8181 /*@C
8182   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
8183 
8184   Not Collective
8185 
8186   Input Parameters:
8187 + dm    - The `DM`
8188 . time  - The time
8189 . funcs - The coordinate functions to evaluate, one per field
8190 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8191 - mode  - The insertion mode for values
8192 
8193   Output Parameter:
8194 . localX - vector
8195 
8196   Calling sequence of `funcs`:
8197 + dim  - The spatial dimension
8198 . time - The current timestep
8199 . x    - The coordinates
8200 . Nc   - The number of components
8201 . u    - The output field values
8202 - ctx  - optional user-defined function context
8203 
8204   Level: developer
8205 
8206   Developer Notes:
8207   This API is specific to only particular usage of `DM`
8208 
8209   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8210 
8211 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8212 @*/
8213 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)
8214 {
8215   PetscFunctionBegin;
8216   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8217   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8218   PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX);
8219   PetscFunctionReturn(PETSC_SUCCESS);
8220 }
8221 
8222 /*@C
8223   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.
8224 
8225   Collective
8226 
8227   Input Parameters:
8228 + dm     - The `DM`
8229 . time   - The time
8230 . numIds - The number of ids
8231 . ids    - The ids
8232 . Nc     - The number of components
8233 . comps  - The components
8234 . label  - The `DMLabel` selecting the portion of the mesh for projection
8235 . funcs  - The coordinate functions to evaluate, one per field
8236 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8237 - mode   - The insertion mode for values
8238 
8239   Output Parameter:
8240 . X - vector
8241 
8242   Calling sequence of `funcs`:
8243 + dim  - The spatial dimension
8244 . time - The current timestep
8245 . x    - The coordinates
8246 . Nc   - The number of components
8247 . u    - The output field values
8248 - ctx  - optional user-defined function context
8249 
8250   Level: developer
8251 
8252   Developer Notes:
8253   This API is specific to only particular usage of `DM`
8254 
8255   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8256 
8257 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8258 @*/
8259 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)
8260 {
8261   Vec localX;
8262 
8263   PetscFunctionBegin;
8264   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8265   PetscCall(DMGetLocalVector(dm, &localX));
8266   PetscCall(VecSet(localX, 0.));
8267   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8268   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8269   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8270   PetscCall(DMRestoreLocalVector(dm, &localX));
8271   PetscFunctionReturn(PETSC_SUCCESS);
8272 }
8273 
8274 /*@C
8275   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.
8276 
8277   Not Collective
8278 
8279   Input Parameters:
8280 + dm     - The `DM`
8281 . time   - The time
8282 . label  - The `DMLabel` selecting the portion of the mesh for projection
8283 . numIds - The number of ids
8284 . ids    - The ids
8285 . Nc     - The number of components
8286 . comps  - The components
8287 . funcs  - The coordinate functions to evaluate, one per field
8288 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8289 - mode   - The insertion mode for values
8290 
8291   Output Parameter:
8292 . localX - vector
8293 
8294   Calling sequence of `funcs`:
8295 + dim  - The spatial dimension
8296 . time - The current time
8297 . x    - The coordinates
8298 . Nc   - The number of components
8299 . u    - The output field values
8300 - ctx  - optional user-defined function context
8301 
8302   Level: developer
8303 
8304   Developer Notes:
8305   This API is specific to only particular usage of `DM`
8306 
8307   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8308 
8309 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8310 @*/
8311 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)
8312 {
8313   PetscFunctionBegin;
8314   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8315   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8316   PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8317   PetscFunctionReturn(PETSC_SUCCESS);
8318 }
8319 
8320 /*@C
8321   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.
8322 
8323   Not Collective
8324 
8325   Input Parameters:
8326 + dm     - The `DM`
8327 . time   - The time
8328 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8329 . funcs  - The functions to evaluate, one per field
8330 - mode   - The insertion mode for values
8331 
8332   Output Parameter:
8333 . localX - The output vector
8334 
8335   Calling sequence of `funcs`:
8336 + dim          - The spatial dimension
8337 . Nf           - The number of input fields
8338 . NfAux        - The number of input auxiliary fields
8339 . uOff         - The offset of each field in u[]
8340 . uOff_x       - The offset of each field in u_x[]
8341 . u            - The field values at this point in space
8342 . u_t          - The field time derivative at this point in space (or NULL)
8343 . u_x          - The field derivatives at this point in space
8344 . aOff         - The offset of each auxiliary field in u[]
8345 . aOff_x       - The offset of each auxiliary field in u_x[]
8346 . a            - The auxiliary field values at this point in space
8347 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8348 . a_x          - The auxiliary field derivatives at this point in space
8349 . t            - The current time
8350 . x            - The coordinates of this point
8351 . numConstants - The number of constants
8352 . constants    - The value of each constant
8353 - f            - The value of the function at this point in space
8354 
8355   Level: intermediate
8356 
8357   Note:
8358   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.
8359   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
8360   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8361   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8362 
8363   Developer Notes:
8364   This API is specific to only particular usage of `DM`
8365 
8366   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8367 
8368 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8369 `DMProjectFunction()`, `DMComputeL2Diff()`
8370 @*/
8371 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)
8372 {
8373   PetscFunctionBegin;
8374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8375   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8376   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8377   PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX);
8378   PetscFunctionReturn(PETSC_SUCCESS);
8379 }
8380 
8381 /*@C
8382   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.
8383 
8384   Not Collective
8385 
8386   Input Parameters:
8387 + dm     - The `DM`
8388 . time   - The time
8389 . label  - The `DMLabel` marking the portion of the domain to output
8390 . numIds - The number of label ids to use
8391 . ids    - The label ids to use for marking
8392 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8393 . comps  - The components to set in the output, or `NULL` for all components
8394 . localU - The input field vector
8395 . funcs  - The functions to evaluate, one per field
8396 - mode   - The insertion mode for values
8397 
8398   Output Parameter:
8399 . localX - The output vector
8400 
8401   Calling sequence of `funcs`:
8402 + dim          - The spatial dimension
8403 . Nf           - The number of input fields
8404 . NfAux        - The number of input auxiliary fields
8405 . uOff         - The offset of each field in u[]
8406 . uOff_x       - The offset of each field in u_x[]
8407 . u            - The field values at this point in space
8408 . u_t          - The field time derivative at this point in space (or NULL)
8409 . u_x          - The field derivatives at this point in space
8410 . aOff         - The offset of each auxiliary field in u[]
8411 . aOff_x       - The offset of each auxiliary field in u_x[]
8412 . a            - The auxiliary field values at this point in space
8413 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8414 . a_x          - The auxiliary field derivatives at this point in space
8415 . t            - The current time
8416 . x            - The coordinates of this point
8417 . numConstants - The number of constants
8418 . constants    - The value of each constant
8419 - f            - The value of the function at this point in space
8420 
8421   Level: intermediate
8422 
8423   Note:
8424   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.
8425   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
8426   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8427   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8428 
8429   Developer Notes:
8430   This API is specific to only particular usage of `DM`
8431 
8432   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8433 
8434 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8435 @*/
8436 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)
8437 {
8438   PetscFunctionBegin;
8439   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8440   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8441   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8442   PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8443   PetscFunctionReturn(PETSC_SUCCESS);
8444 }
8445 
8446 /*@C
8447   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.
8448 
8449   Not Collective
8450 
8451   Input Parameters:
8452 + dm     - The `DM`
8453 . time   - The time
8454 . label  - The `DMLabel` marking the portion of the domain to output
8455 . numIds - The number of label ids to use
8456 . ids    - The label ids to use for marking
8457 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8458 . comps  - The components to set in the output, or `NULL` for all components
8459 . U      - The input field vector
8460 . funcs  - The functions to evaluate, one per field
8461 - mode   - The insertion mode for values
8462 
8463   Output Parameter:
8464 . X - The output vector
8465 
8466   Calling sequence of `funcs`:
8467 + dim          - The spatial dimension
8468 . Nf           - The number of input fields
8469 . NfAux        - The number of input auxiliary fields
8470 . uOff         - The offset of each field in u[]
8471 . uOff_x       - The offset of each field in u_x[]
8472 . u            - The field values at this point in space
8473 . u_t          - The field time derivative at this point in space (or NULL)
8474 . u_x          - The field derivatives at this point in space
8475 . aOff         - The offset of each auxiliary field in u[]
8476 . aOff_x       - The offset of each auxiliary field in u_x[]
8477 . a            - The auxiliary field values at this point in space
8478 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8479 . a_x          - The auxiliary field derivatives at this point in space
8480 . t            - The current time
8481 . x            - The coordinates of this point
8482 . numConstants - The number of constants
8483 . constants    - The value of each constant
8484 - f            - The value of the function at this point in space
8485 
8486   Level: intermediate
8487 
8488   Note:
8489   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.
8490   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
8491   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8492   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8493 
8494   Developer Notes:
8495   This API is specific to only particular usage of `DM`
8496 
8497   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8498 
8499 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8500 @*/
8501 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)
8502 {
8503   DM  dmIn;
8504   Vec localU, localX;
8505 
8506   PetscFunctionBegin;
8507   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8508   PetscCall(VecGetDM(U, &dmIn));
8509   PetscCall(DMGetLocalVector(dmIn, &localU));
8510   PetscCall(DMGetLocalVector(dm, &localX));
8511   PetscCall(VecSet(localX, 0.));
8512   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8513   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8514   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8515   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8516   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8517   PetscCall(DMRestoreLocalVector(dm, &localX));
8518   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8519   PetscFunctionReturn(PETSC_SUCCESS);
8520 }
8521 
8522 /*@C
8523   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.
8524 
8525   Not Collective
8526 
8527   Input Parameters:
8528 + dm     - The `DM`
8529 . time   - The time
8530 . label  - The `DMLabel` marking the portion of the domain boundary to output
8531 . numIds - The number of label ids to use
8532 . ids    - The label ids to use for marking
8533 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8534 . comps  - The components to set in the output, or `NULL` for all components
8535 . localU - The input field vector
8536 . funcs  - The functions to evaluate, one per field
8537 - mode   - The insertion mode for values
8538 
8539   Output Parameter:
8540 . localX - The output vector
8541 
8542   Calling sequence of `funcs`:
8543 + dim          - The spatial dimension
8544 . Nf           - The number of input fields
8545 . NfAux        - The number of input auxiliary fields
8546 . uOff         - The offset of each field in u[]
8547 . uOff_x       - The offset of each field in u_x[]
8548 . u            - The field values at this point in space
8549 . u_t          - The field time derivative at this point in space (or NULL)
8550 . u_x          - The field derivatives at this point in space
8551 . aOff         - The offset of each auxiliary field in u[]
8552 . aOff_x       - The offset of each auxiliary field in u_x[]
8553 . a            - The auxiliary field values at this point in space
8554 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8555 . a_x          - The auxiliary field derivatives at this point in space
8556 . t            - The current time
8557 . x            - The coordinates of this point
8558 . n            - The face normal
8559 . numConstants - The number of constants
8560 . constants    - The value of each constant
8561 - f            - The value of the function at this point in space
8562 
8563   Level: intermediate
8564 
8565   Note:
8566   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.
8567   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
8568   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8569   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8570 
8571   Developer Notes:
8572   This API is specific to only particular usage of `DM`
8573 
8574   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8575 
8576 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8577 @*/
8578 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)
8579 {
8580   PetscFunctionBegin;
8581   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8582   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8583   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8584   PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8585   PetscFunctionReturn(PETSC_SUCCESS);
8586 }
8587 
8588 /*@C
8589   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8590 
8591   Collective
8592 
8593   Input Parameters:
8594 + dm    - The `DM`
8595 . time  - The time
8596 . funcs - The functions to evaluate for each field component
8597 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8598 - X     - The coefficient vector u_h, a global vector
8599 
8600   Output Parameter:
8601 . diff - The diff ||u - u_h||_2
8602 
8603   Level: developer
8604 
8605   Developer Notes:
8606   This API is specific to only particular usage of `DM`
8607 
8608   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8609 
8610 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8611 @*/
8612 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8613 {
8614   PetscFunctionBegin;
8615   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8616   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8617   PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff);
8618   PetscFunctionReturn(PETSC_SUCCESS);
8619 }
8620 
8621 /*@C
8622   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8623 
8624   Collective
8625 
8626   Input Parameters:
8627 + dm    - The `DM`
8628 . time  - The time
8629 . funcs - The gradient functions to evaluate for each field component
8630 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8631 . X     - The coefficient vector u_h, a global vector
8632 - n     - The vector to project along
8633 
8634   Output Parameter:
8635 . diff - The diff ||(grad u - grad u_h) . n||_2
8636 
8637   Level: developer
8638 
8639   Developer Notes:
8640   This API is specific to only particular usage of `DM`
8641 
8642   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8643 
8644 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8645 @*/
8646 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)
8647 {
8648   PetscFunctionBegin;
8649   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8650   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8651   PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff);
8652   PetscFunctionReturn(PETSC_SUCCESS);
8653 }
8654 
8655 /*@C
8656   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8657 
8658   Collective
8659 
8660   Input Parameters:
8661 + dm    - The `DM`
8662 . time  - The time
8663 . funcs - The functions to evaluate for each field component
8664 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8665 - X     - The coefficient vector u_h, a global vector
8666 
8667   Output Parameter:
8668 . diff - The array of differences, ||u^f - u^f_h||_2
8669 
8670   Level: developer
8671 
8672   Developer Notes:
8673   This API is specific to only particular usage of `DM`
8674 
8675   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8676 
8677 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8678 @*/
8679 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8680 {
8681   PetscFunctionBegin;
8682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8683   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8684   PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff);
8685   PetscFunctionReturn(PETSC_SUCCESS);
8686 }
8687 
8688 /*@C
8689   DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8690 
8691   Not Collective
8692 
8693   Input Parameter:
8694 . dm - The `DM`
8695 
8696   Output Parameters:
8697 + nranks - the number of neighbours
8698 - ranks  - the neighbors ranks
8699 
8700   Level: beginner
8701 
8702   Note:
8703   Do not free the array, it is freed when the `DM` is destroyed.
8704 
8705 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8706 @*/
8707 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8708 {
8709   PetscFunctionBegin;
8710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8711   PetscUseTypeMethod(dm, getneighbors, nranks, ranks);
8712   PetscFunctionReturn(PETSC_SUCCESS);
8713 }
8714 
8715 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8716 
8717 /*
8718     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8719     This must be a different function because it requires DM which is not defined in the Mat library
8720 */
8721 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8722 {
8723   PetscFunctionBegin;
8724   if (coloring->ctype == IS_COLORING_LOCAL) {
8725     Vec x1local;
8726     DM  dm;
8727     PetscCall(MatGetDM(J, &dm));
8728     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8729     PetscCall(DMGetLocalVector(dm, &x1local));
8730     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8731     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8732     x1 = x1local;
8733   }
8734   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8735   if (coloring->ctype == IS_COLORING_LOCAL) {
8736     DM dm;
8737     PetscCall(MatGetDM(J, &dm));
8738     PetscCall(DMRestoreLocalVector(dm, &x1));
8739   }
8740   PetscFunctionReturn(PETSC_SUCCESS);
8741 }
8742 
8743 /*@
8744   MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8745 
8746   Input Parameters:
8747 + coloring   - The matrix to get the `DM` from
8748 - fdcoloring - the `MatFDColoring` object
8749 
8750   Level: advanced
8751 
8752   Developer Note:
8753   This routine exists because the PETSc `Mat` library does not know about the `DM` objects
8754 
8755 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8756 @*/
8757 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8758 {
8759   PetscFunctionBegin;
8760   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8761   PetscFunctionReturn(PETSC_SUCCESS);
8762 }
8763 
8764 /*@
8765   DMGetCompatibility - determine if two `DM`s are compatible
8766 
8767   Collective
8768 
8769   Input Parameters:
8770 + dm1 - the first `DM`
8771 - dm2 - the second `DM`
8772 
8773   Output Parameters:
8774 + compatible - whether or not the two `DM`s are compatible
8775 - set        - whether or not the compatible value was actually determined and set
8776 
8777   Level: advanced
8778 
8779   Notes:
8780   Two `DM`s are deemed compatible if they represent the same parallel decomposition
8781   of the same topology. This implies that the section (field data) on one
8782   "makes sense" with respect to the topology and parallel decomposition of the other.
8783   Loosely speaking, compatible `DM`s represent the same domain and parallel
8784   decomposition, but hold different data.
8785 
8786   Typically, one would confirm compatibility if intending to simultaneously iterate
8787   over a pair of vectors obtained from different `DM`s.
8788 
8789   For example, two `DMDA` objects are compatible if they have the same local
8790   and global sizes and the same stencil width. They can have different numbers
8791   of degrees of freedom per node. Thus, one could use the node numbering from
8792   either `DM` in bounds for a loop over vectors derived from either `DM`.
8793 
8794   Consider the operation of summing data living on a 2-dof `DMDA` to data living
8795   on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8796 .vb
8797   ...
8798   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8799   if (set && compatible)  {
8800     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8801     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8802     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8803     for (j=y; j<y+n; ++j) {
8804       for (i=x; i<x+m, ++i) {
8805         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8806       }
8807     }
8808     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8809     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8810   } else {
8811     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8812   }
8813   ...
8814 .ve
8815 
8816   Checking compatibility might be expensive for a given implementation of `DM`,
8817   or might be impossible to unambiguously confirm or deny. For this reason,
8818   this function may decline to determine compatibility, and hence users should
8819   always check the "set" output parameter.
8820 
8821   A `DM` is always compatible with itself.
8822 
8823   In the current implementation, `DM`s which live on "unequal" communicators
8824   (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8825   incompatible.
8826 
8827   This function is labeled "Collective," as information about all subdomains
8828   is required on each rank. However, in `DM` implementations which store all this
8829   information locally, this function may be merely "Logically Collective".
8830 
8831   Developer Note:
8832   Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8833   iff B is compatible with A. Thus, this function checks the implementations
8834   of both dm and dmc (if they are of different types), attempting to determine
8835   compatibility. It is left to `DM` implementers to ensure that symmetry is
8836   preserved. The simplest way to do this is, when implementing type-specific
8837   logic for this function, is to check for existing logic in the implementation
8838   of other `DM` types and let *set = PETSC_FALSE if found.
8839 
8840 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8841 @*/
8842 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8843 {
8844   PetscMPIInt compareResult;
8845   DMType      type, type2;
8846   PetscBool   sameType;
8847 
8848   PetscFunctionBegin;
8849   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8850   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8851 
8852   /* Declare a DM compatible with itself */
8853   if (dm1 == dm2) {
8854     *set        = PETSC_TRUE;
8855     *compatible = PETSC_TRUE;
8856     PetscFunctionReturn(PETSC_SUCCESS);
8857   }
8858 
8859   /* Declare a DM incompatible with a DM that lives on an "unequal"
8860      communicator. Note that this does not preclude compatibility with
8861      DMs living on "congruent" or "similar" communicators, but this must be
8862      determined by the implementation-specific logic */
8863   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8864   if (compareResult == MPI_UNEQUAL) {
8865     *set        = PETSC_TRUE;
8866     *compatible = PETSC_FALSE;
8867     PetscFunctionReturn(PETSC_SUCCESS);
8868   }
8869 
8870   /* Pass to the implementation-specific routine, if one exists. */
8871   if (dm1->ops->getcompatibility) {
8872     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8873     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8874   }
8875 
8876   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8877      with an implementation of this function from dm2 */
8878   PetscCall(DMGetType(dm1, &type));
8879   PetscCall(DMGetType(dm2, &type2));
8880   PetscCall(PetscStrcmp(type, type2, &sameType));
8881   if (!sameType && dm2->ops->getcompatibility) {
8882     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8883   } else {
8884     *set = PETSC_FALSE;
8885   }
8886   PetscFunctionReturn(PETSC_SUCCESS);
8887 }
8888 
8889 /*@C
8890   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8891 
8892   Logically Collective
8893 
8894   Input Parameters:
8895 + dm             - the `DM`
8896 . f              - the monitor function
8897 . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8898 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`)
8899 
8900   Options Database Key:
8901 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8902                             does not cancel those set via the options database.
8903 
8904   Level: intermediate
8905 
8906   Note:
8907   Several different monitoring routines may be set by calling
8908   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8909   order in which they were set.
8910 
8911   Fortran Note:
8912   Only a single monitor function can be set for each `DM` object
8913 
8914   Developer Note:
8915   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8916 
8917 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8918 @*/
8919 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8920 {
8921   PetscInt m;
8922 
8923   PetscFunctionBegin;
8924   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8925   for (m = 0; m < dm->numbermonitors; ++m) {
8926     PetscBool identical;
8927 
8928     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))f, mctx, monitordestroy, (PetscErrorCode (*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8929     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
8930   }
8931   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8932   dm->monitor[dm->numbermonitors]          = f;
8933   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8934   dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8935   PetscFunctionReturn(PETSC_SUCCESS);
8936 }
8937 
8938 /*@
8939   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8940 
8941   Logically Collective
8942 
8943   Input Parameter:
8944 . dm - the DM
8945 
8946   Options Database Key:
8947 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8948   into a code by calls to `DMonitorSet()`, but does not cancel those
8949   set via the options database
8950 
8951   Level: intermediate
8952 
8953   Note:
8954   There is no way to clear one specific monitor from a `DM` object.
8955 
8956 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8957 @*/
8958 PetscErrorCode DMMonitorCancel(DM dm)
8959 {
8960   PetscInt m;
8961 
8962   PetscFunctionBegin;
8963   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8964   for (m = 0; m < dm->numbermonitors; ++m) {
8965     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8966   }
8967   dm->numbermonitors = 0;
8968   PetscFunctionReturn(PETSC_SUCCESS);
8969 }
8970 
8971 /*@C
8972   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8973 
8974   Collective
8975 
8976   Input Parameters:
8977 + dm           - `DM` object you wish to monitor
8978 . name         - the monitor type one is seeking
8979 . help         - message indicating what monitoring is done
8980 . manual       - manual page for the monitor
8981 . monitor      - the monitor function
8982 - 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
8983 
8984   Output Parameter:
8985 . flg - Flag set if the monitor was created
8986 
8987   Level: developer
8988 
8989 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8990           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8991           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
8992           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8993           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8994           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8995           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8996 @*/
8997 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8998 {
8999   PetscViewer       viewer;
9000   PetscViewerFormat format;
9001 
9002   PetscFunctionBegin;
9003   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9004   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
9005   if (*flg) {
9006     PetscViewerAndFormat *vf;
9007 
9008     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
9009     PetscCall(PetscViewerDestroy(&viewer));
9010     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
9011     PetscCall(DMMonitorSet(dm, (PetscErrorCode (*)(DM, void *))monitor, vf, (PetscErrorCode (*)(void **))PetscViewerAndFormatDestroy));
9012   }
9013   PetscFunctionReturn(PETSC_SUCCESS);
9014 }
9015 
9016 /*@
9017   DMMonitor - runs the user provided monitor routines, if they exist
9018 
9019   Collective
9020 
9021   Input Parameter:
9022 . dm - The `DM`
9023 
9024   Level: developer
9025 
9026   Developer Note:
9027   Note should indicate when during the life of the `DM` the monitor is run. It appears to be
9028   related to the discretization process seems rather specialized since some `DM` have no
9029   concept of discretization.
9030 
9031 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
9032 @*/
9033 PetscErrorCode DMMonitor(DM dm)
9034 {
9035   PetscInt m;
9036 
9037   PetscFunctionBegin;
9038   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
9039   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9040   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9041   PetscFunctionReturn(PETSC_SUCCESS);
9042 }
9043 
9044 /*@
9045   DMComputeError - Computes the error assuming the user has provided the exact solution functions
9046 
9047   Collective
9048 
9049   Input Parameters:
9050 + dm  - The `DM`
9051 - sol - The solution vector
9052 
9053   Input/Output Parameter:
9054 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
9055            contains the error in each field
9056 
9057   Output Parameter:
9058 . errorVec - A vector to hold the cellwise error (may be `NULL`)
9059 
9060   Level: developer
9061 
9062   Note:
9063   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
9064 
9065 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9066 @*/
9067 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9068 {
9069   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9070   void    **ctxs;
9071   PetscReal time;
9072   PetscInt  Nf, f, Nds, s;
9073 
9074   PetscFunctionBegin;
9075   PetscCall(DMGetNumFields(dm, &Nf));
9076   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9077   PetscCall(DMGetNumDS(dm, &Nds));
9078   for (s = 0; s < Nds; ++s) {
9079     PetscDS         ds;
9080     DMLabel         label;
9081     IS              fieldIS;
9082     const PetscInt *fields;
9083     PetscInt        dsNf;
9084 
9085     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
9086     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9087     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9088     for (f = 0; f < dsNf; ++f) {
9089       const PetscInt field = fields[f];
9090       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9091     }
9092     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9093   }
9094   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);
9095   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9096   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9097   if (errorVec) {
9098     DM             edm;
9099     DMPolytopeType ct;
9100     PetscBool      simplex;
9101     PetscInt       dim, cStart, Nf;
9102 
9103     PetscCall(DMClone(dm, &edm));
9104     PetscCall(DMGetDimension(edm, &dim));
9105     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9106     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9107     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9108     PetscCall(DMGetNumFields(dm, &Nf));
9109     for (f = 0; f < Nf; ++f) {
9110       PetscFE         fe, efe;
9111       PetscQuadrature q;
9112       const char     *name;
9113 
9114       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
9115       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9116       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
9117       PetscCall(PetscObjectSetName((PetscObject)efe, name));
9118       PetscCall(PetscFEGetQuadrature(fe, &q));
9119       PetscCall(PetscFESetQuadrature(efe, q));
9120       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
9121       PetscCall(PetscFEDestroy(&efe));
9122     }
9123     PetscCall(DMCreateDS(edm));
9124 
9125     PetscCall(DMCreateGlobalVector(edm, errorVec));
9126     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
9127     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9128     PetscCall(DMDestroy(&edm));
9129   }
9130   PetscCall(PetscFree2(exactSol, ctxs));
9131   PetscFunctionReturn(PETSC_SUCCESS);
9132 }
9133 
9134 /*@
9135   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
9136 
9137   Not Collective
9138 
9139   Input Parameter:
9140 . dm - The `DM`
9141 
9142   Output Parameter:
9143 . numAux - The number of auxiliary data vectors
9144 
9145   Level: advanced
9146 
9147 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
9148 @*/
9149 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9150 {
9151   PetscFunctionBegin;
9152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9153   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9154   PetscFunctionReturn(PETSC_SUCCESS);
9155 }
9156 
9157 /*@
9158   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9159 
9160   Not Collective
9161 
9162   Input Parameters:
9163 + dm    - The `DM`
9164 . label - The `DMLabel`
9165 . value - The label value indicating the region
9166 - part  - The equation part, or 0 if unused
9167 
9168   Output Parameter:
9169 . aux - The `Vec` holding auxiliary field data
9170 
9171   Level: advanced
9172 
9173   Note:
9174   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9175 
9176 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
9177 @*/
9178 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9179 {
9180   PetscHashAuxKey key, wild = {NULL, 0, 0};
9181   PetscBool       has;
9182 
9183   PetscFunctionBegin;
9184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9185   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9186   key.label = label;
9187   key.value = value;
9188   key.part  = part;
9189   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9190   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
9191   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9192   PetscFunctionReturn(PETSC_SUCCESS);
9193 }
9194 
9195 /*@
9196   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
9197 
9198   Not Collective because auxiliary vectors are not parallel
9199 
9200   Input Parameters:
9201 + dm    - The `DM`
9202 . label - The `DMLabel`
9203 . value - The label value indicating the region
9204 . part  - The equation part, or 0 if unused
9205 - aux   - The `Vec` holding auxiliary field data
9206 
9207   Level: advanced
9208 
9209 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
9210 @*/
9211 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9212 {
9213   Vec             old;
9214   PetscHashAuxKey key;
9215 
9216   PetscFunctionBegin;
9217   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9218   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9219   key.label = label;
9220   key.value = value;
9221   key.part  = part;
9222   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9223   PetscCall(PetscObjectReference((PetscObject)aux));
9224   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9225   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9226   PetscCall(VecDestroy(&old));
9227   PetscFunctionReturn(PETSC_SUCCESS);
9228 }
9229 
9230 /*@
9231   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9232 
9233   Not Collective
9234 
9235   Input Parameter:
9236 . dm - The `DM`
9237 
9238   Output Parameters:
9239 + labels - The `DMLabel`s for each `Vec`
9240 . values - The label values for each `Vec`
9241 - parts  - The equation parts for each `Vec`
9242 
9243   Level: advanced
9244 
9245   Note:
9246   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9247 
9248 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9249 @*/
9250 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9251 {
9252   PetscHashAuxKey *keys;
9253   PetscInt         n, i, off = 0;
9254 
9255   PetscFunctionBegin;
9256   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9257   PetscAssertPointer(labels, 2);
9258   PetscAssertPointer(values, 3);
9259   PetscAssertPointer(parts, 4);
9260   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9261   PetscCall(PetscMalloc1(n, &keys));
9262   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9263   for (i = 0; i < n; ++i) {
9264     labels[i] = keys[i].label;
9265     values[i] = keys[i].value;
9266     parts[i]  = keys[i].part;
9267   }
9268   PetscCall(PetscFree(keys));
9269   PetscFunctionReturn(PETSC_SUCCESS);
9270 }
9271 
9272 /*@
9273   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9274 
9275   Not Collective
9276 
9277   Input Parameter:
9278 . dm - The `DM`
9279 
9280   Output Parameter:
9281 . dmNew - The new `DM`, now with the same auxiliary data
9282 
9283   Level: advanced
9284 
9285   Note:
9286   This is a shallow copy of the auxiliary vectors
9287 
9288 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9289 @*/
9290 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9291 {
9292   PetscFunctionBegin;
9293   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9294   PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2);
9295   if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS);
9296   PetscCall(DMClearAuxiliaryVec(dmNew));
9297 
9298   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9299   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9300   {
9301     Vec     *auxData;
9302     PetscInt n, i, off = 0;
9303 
9304     PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n));
9305     PetscCall(PetscMalloc1(n, &auxData));
9306     PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData));
9307     for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i]));
9308     PetscCall(PetscFree(auxData));
9309   }
9310   PetscFunctionReturn(PETSC_SUCCESS);
9311 }
9312 
9313 /*@
9314   DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one
9315 
9316   Not Collective
9317 
9318   Input Parameter:
9319 . dm - The `DM`
9320 
9321   Level: advanced
9322 
9323 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9324 @*/
9325 PetscErrorCode DMClearAuxiliaryVec(DM dm)
9326 {
9327   Vec     *auxData;
9328   PetscInt n, i, off = 0;
9329 
9330   PetscFunctionBegin;
9331   PetscCall(PetscHMapAuxGetSize(dm->auxData, &n));
9332   PetscCall(PetscMalloc1(n, &auxData));
9333   PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData));
9334   for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i]));
9335   PetscCall(PetscFree(auxData));
9336   PetscCall(PetscHMapAuxDestroy(&dm->auxData));
9337   PetscCall(PetscHMapAuxCreate(&dm->auxData));
9338   PetscFunctionReturn(PETSC_SUCCESS);
9339 }
9340 
9341 /*@
9342   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9343 
9344   Not Collective
9345 
9346   Input Parameters:
9347 + ct         - The `DMPolytopeType`
9348 . sourceCone - The source arrangement of faces
9349 - targetCone - The target arrangement of faces
9350 
9351   Output Parameters:
9352 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9353 - found - Flag indicating that a suitable orientation was found
9354 
9355   Level: advanced
9356 
9357   Note:
9358   An arrangement is a face order combined with an orientation for each face
9359 
9360   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9361   that labels each arrangement (face ordering plus orientation for each face).
9362 
9363   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9364 
9365 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9366 @*/
9367 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9368 {
9369   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9370   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9371   PetscInt       o, c;
9372 
9373   PetscFunctionBegin;
9374   if (!nO) {
9375     *ornt  = 0;
9376     *found = PETSC_TRUE;
9377     PetscFunctionReturn(PETSC_SUCCESS);
9378   }
9379   for (o = -nO; o < nO; ++o) {
9380     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
9381 
9382     for (c = 0; c < cS; ++c)
9383       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9384     if (c == cS) {
9385       *ornt = o;
9386       break;
9387     }
9388   }
9389   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9390   PetscFunctionReturn(PETSC_SUCCESS);
9391 }
9392 
9393 /*@
9394   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9395 
9396   Not Collective
9397 
9398   Input Parameters:
9399 + ct         - The `DMPolytopeType`
9400 . sourceCone - The source arrangement of faces
9401 - targetCone - The target arrangement of faces
9402 
9403   Output Parameter:
9404 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9405 
9406   Level: advanced
9407 
9408   Note:
9409   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9410 
9411   Developer Note:
9412   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9413 
9414 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9415 @*/
9416 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9417 {
9418   PetscBool found;
9419 
9420   PetscFunctionBegin;
9421   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9422   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9423   PetscFunctionReturn(PETSC_SUCCESS);
9424 }
9425 
9426 /*@
9427   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9428 
9429   Not Collective
9430 
9431   Input Parameters:
9432 + ct         - The `DMPolytopeType`
9433 . sourceVert - The source arrangement of vertices
9434 - targetVert - The target arrangement of vertices
9435 
9436   Output Parameters:
9437 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9438 - found - Flag indicating that a suitable orientation was found
9439 
9440   Level: advanced
9441 
9442   Notes:
9443   An arrangement is a vertex order
9444 
9445   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9446   that labels each arrangement (vertex ordering).
9447 
9448   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9449 
9450 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()`
9451 @*/
9452 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9453 {
9454   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9455   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9456   PetscInt       o, c;
9457 
9458   PetscFunctionBegin;
9459   if (!nO) {
9460     *ornt  = 0;
9461     *found = PETSC_TRUE;
9462     PetscFunctionReturn(PETSC_SUCCESS);
9463   }
9464   for (o = -nO; o < nO; ++o) {
9465     const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o);
9466 
9467     for (c = 0; c < cS; ++c)
9468       if (sourceVert[arr[c]] != targetVert[c]) break;
9469     if (c == cS) {
9470       *ornt = o;
9471       break;
9472     }
9473   }
9474   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9475   PetscFunctionReturn(PETSC_SUCCESS);
9476 }
9477 
9478 /*@
9479   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9480 
9481   Not Collective
9482 
9483   Input Parameters:
9484 + ct         - The `DMPolytopeType`
9485 . sourceCone - The source arrangement of vertices
9486 - targetCone - The target arrangement of vertices
9487 
9488   Output Parameter:
9489 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9490 
9491   Level: advanced
9492 
9493   Note:
9494   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9495 
9496   Developer Note:
9497   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9498 
9499 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9500 @*/
9501 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9502 {
9503   PetscBool found;
9504 
9505   PetscFunctionBegin;
9506   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9507   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9508   PetscFunctionReturn(PETSC_SUCCESS);
9509 }
9510 
9511 /*@
9512   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9513 
9514   Not Collective
9515 
9516   Input Parameters:
9517 + ct    - The `DMPolytopeType`
9518 - point - Coordinates of the point
9519 
9520   Output Parameter:
9521 . inside - Flag indicating whether the point is inside the reference cell of given type
9522 
9523   Level: advanced
9524 
9525 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9526 @*/
9527 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9528 {
9529   PetscReal sum = 0.0;
9530   PetscInt  d;
9531 
9532   PetscFunctionBegin;
9533   *inside = PETSC_TRUE;
9534   switch (ct) {
9535   case DM_POLYTOPE_TRIANGLE:
9536   case DM_POLYTOPE_TETRAHEDRON:
9537     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9538       if (point[d] < -1.0) {
9539         *inside = PETSC_FALSE;
9540         break;
9541       }
9542       sum += point[d];
9543     }
9544     if (sum > PETSC_SMALL) {
9545       *inside = PETSC_FALSE;
9546       break;
9547     }
9548     break;
9549   case DM_POLYTOPE_QUADRILATERAL:
9550   case DM_POLYTOPE_HEXAHEDRON:
9551     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9552       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9553         *inside = PETSC_FALSE;
9554         break;
9555       }
9556     break;
9557   default:
9558     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9559   }
9560   PetscFunctionReturn(PETSC_SUCCESS);
9561 }
9562 
9563 /*@
9564   DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default
9565 
9566   Logically collective
9567 
9568   Input Parameters:
9569 + dm      - The DM
9570 - reorder - Flag for reordering
9571 
9572   Level: intermediate
9573 
9574 .seealso: `DMReorderSectionGetDefault()`
9575 @*/
9576 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder)
9577 {
9578   PetscFunctionBegin;
9579   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9580   PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder));
9581   PetscFunctionReturn(PETSC_SUCCESS);
9582 }
9583 
9584 /*@
9585   DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default
9586 
9587   Not collective
9588 
9589   Input Parameter:
9590 . dm - The DM
9591 
9592   Output Parameter:
9593 . reorder - Flag for reordering
9594 
9595   Level: intermediate
9596 
9597 .seealso: `DMReorderSetDefault()`
9598 @*/
9599 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder)
9600 {
9601   PetscFunctionBegin;
9602   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9603   PetscAssertPointer(reorder, 2);
9604   *reorder = DM_REORDER_DEFAULT_NOTSET;
9605   PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder));
9606   PetscFunctionReturn(PETSC_SUCCESS);
9607 }
9608 
9609 /*@
9610   DMReorderSectionSetType - Set the type of local section reordering
9611 
9612   Logically collective
9613 
9614   Input Parameters:
9615 + dm      - The DM
9616 - reorder - The reordering method
9617 
9618   Level: intermediate
9619 
9620 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()`
9621 @*/
9622 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder)
9623 {
9624   PetscFunctionBegin;
9625   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9626   PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder));
9627   PetscFunctionReturn(PETSC_SUCCESS);
9628 }
9629 
9630 /*@
9631   DMReorderSectionGetType - Get the reordering type for the local section
9632 
9633   Not collective
9634 
9635   Input Parameter:
9636 . dm - The DM
9637 
9638   Output Parameter:
9639 . reorder - The reordering method
9640 
9641   Level: intermediate
9642 
9643 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()`
9644 @*/
9645 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder)
9646 {
9647   PetscFunctionBegin;
9648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9649   PetscAssertPointer(reorder, 2);
9650   *reorder = NULL;
9651   PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder));
9652   PetscFunctionReturn(PETSC_SUCCESS);
9653 }
9654