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