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