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