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