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