xref: /petsc/src/dm/interface/dm.c (revision 6f77c9fc6cc32030568bdf5e4f442ea7249c2b90)
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 /*@
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 /*@
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   PetscInt Nf, Nds, s;
5969 
5970   PetscFunctionBegin;
5971   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5972   if (u) PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
5973   if (u_t) PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
5974   PetscCall(DMGetNumFields(dm, &Nf));
5975   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
5976   PetscCall(DMGetNumDS(dm, &Nds));
5977   for (s = 0; s < Nds; ++s) {
5978     PetscDS         ds;
5979     DMLabel         label;
5980     IS              fieldIS;
5981     const PetscInt *fields, id = 1;
5982     PetscInt        dsNf, f;
5983 
5984     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
5985     PetscCall(PetscDSGetNumFields(ds, &dsNf));
5986     PetscCall(ISGetIndices(fieldIS, &fields));
5987     PetscCall(PetscArrayzero(exacts, Nf));
5988     PetscCall(PetscArrayzero(ectxs, Nf));
5989     if (u) {
5990       for (f = 0; f < dsNf; ++f) {
5991         const PetscInt field = fields[f];
5992         PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
5993       }
5994       PetscCall(ISRestoreIndices(fieldIS, &fields));
5995       if (label) {
5996         PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u));
5997       } else {
5998         PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u));
5999       }
6000     }
6001     if (u_t) {
6002       PetscCall(PetscArrayzero(exacts, Nf));
6003       PetscCall(PetscArrayzero(ectxs, Nf));
6004       for (f = 0; f < dsNf; ++f) {
6005         const PetscInt field = fields[f];
6006         PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]));
6007       }
6008       PetscCall(ISRestoreIndices(fieldIS, &fields));
6009       if (label) {
6010         PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t));
6011       } else {
6012         PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t));
6013       }
6014     }
6015   }
6016   if (u) {
6017     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6018     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6019   }
6020   if (u_t) {
6021     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6022     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6023   }
6024   PetscCall(PetscFree2(exacts, ectxs));
6025   PetscFunctionReturn(0);
6026 }
6027 
6028 PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
6029 {
6030   PetscDS    dsNew;
6031   DSBoundary b;
6032   PetscInt   cdim, Nf, f, d;
6033   PetscBool  isCohesive;
6034   void      *ctx;
6035 
6036   PetscFunctionBegin;
6037   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6038   PetscCall(PetscDSCopyConstants(ds, dsNew));
6039   PetscCall(PetscDSCopyExactSolutions(ds, dsNew));
6040   PetscCall(PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew));
6041   PetscCall(PetscDSCopyEquations(ds, dsNew));
6042   PetscCall(PetscDSGetNumFields(ds, &Nf));
6043   for (f = 0; f < Nf; ++f) {
6044     PetscCall(PetscDSGetContext(ds, f, &ctx));
6045     PetscCall(PetscDSSetContext(dsNew, f, ctx));
6046     PetscCall(PetscDSGetCohesive(ds, f, &isCohesive));
6047     PetscCall(PetscDSSetCohesive(dsNew, f, isCohesive));
6048     PetscCall(PetscDSGetJetDegree(ds, f, &d));
6049     PetscCall(PetscDSSetJetDegree(dsNew, f, d));
6050   }
6051   if (Nf) {
6052     PetscCall(PetscDSGetCoordinateDimension(ds, &cdim));
6053     PetscCall(PetscDSSetCoordinateDimension(dsNew, cdim));
6054   }
6055   PetscCall(PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew));
6056   for (b = dsNew->boundary; b; b = b->next) {
6057     PetscCall(DMGetLabel(dm, b->lname, &b->label));
6058     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
6059     //PetscCheck(b->label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
6060   }
6061 
6062   PetscCall(DMSetRegionDS(dm, label, fields, dsNew));
6063   PetscCall(PetscDSDestroy(&dsNew));
6064   PetscFunctionReturn(0);
6065 }
6066 
6067 /*@
6068   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6069 
6070   Collective on dm
6071 
6072   Input Parameter:
6073 . dm - The `DM`
6074 
6075   Output Parameter:
6076 . newdm - The `DM`
6077 
6078   Level: advanced
6079 
6080 .seealso: `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6081 @*/
6082 PetscErrorCode DMCopyDS(DM dm, DM newdm)
6083 {
6084   PetscInt Nds, s;
6085 
6086   PetscFunctionBegin;
6087   if (dm == newdm) PetscFunctionReturn(0);
6088   PetscCall(DMGetNumDS(dm, &Nds));
6089   PetscCall(DMClearDS(newdm));
6090   for (s = 0; s < Nds; ++s) {
6091     DMLabel  label;
6092     IS       fields;
6093     PetscDS  ds, newds;
6094     PetscInt Nbd, bd;
6095 
6096     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds));
6097     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6098     PetscCall(DMTransferDS_Internal(newdm, label, fields, ds));
6099     /* Complete new labels in the new DS */
6100     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds));
6101     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6102     for (bd = 0; bd < Nbd; ++bd) {
6103       PetscWeakForm wf;
6104       DMLabel       label;
6105       PetscInt      field;
6106 
6107       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6108       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6109     }
6110   }
6111   PetscCall(DMCompleteBCLabels_Internal(newdm));
6112   PetscFunctionReturn(0);
6113 }
6114 
6115 /*@
6116   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6117 
6118   Collective on dm
6119 
6120   Input Parameter:
6121 . dm - The `DM`
6122 
6123   Output Parameter:
6124 . newdm - The `DM`
6125 
6126   Level: advanced
6127 
6128   Developer Note:
6129   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6130 
6131 .seealso: `DMCopyFields()`, `DMCopyDS()`
6132 @*/
6133 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6134 {
6135   PetscFunctionBegin;
6136   PetscCall(DMCopyFields(dm, newdm));
6137   PetscCall(DMCopyDS(dm, newdm));
6138   PetscFunctionReturn(0);
6139 }
6140 
6141 /*@
6142   DMGetDimension - Return the topological dimension of the `DM`
6143 
6144   Not collective
6145 
6146   Input Parameter:
6147 . dm - The `DM`
6148 
6149   Output Parameter:
6150 . dim - The topological dimension
6151 
6152   Level: beginner
6153 
6154 .seealso: `DMSetDimension()`, `DMCreate()`
6155 @*/
6156 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6157 {
6158   PetscFunctionBegin;
6159   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6160   PetscValidIntPointer(dim, 2);
6161   *dim = dm->dim;
6162   PetscFunctionReturn(0);
6163 }
6164 
6165 /*@
6166   DMSetDimension - Set the topological dimension of the `DM`
6167 
6168   Collective on dm
6169 
6170   Input Parameters:
6171 + dm - The `DM`
6172 - dim - The topological dimension
6173 
6174   Level: beginner
6175 
6176 .seealso: `DMGetDimension()`, `DMCreate()`
6177 @*/
6178 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6179 {
6180   PetscDS  ds;
6181   PetscInt Nds, n;
6182 
6183   PetscFunctionBegin;
6184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6185   PetscValidLogicalCollectiveInt(dm, dim, 2);
6186   dm->dim = dim;
6187   if (dm->dim >= 0) {
6188     PetscCall(DMGetNumDS(dm, &Nds));
6189     for (n = 0; n < Nds; ++n) {
6190       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds));
6191       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6192     }
6193   }
6194   PetscFunctionReturn(0);
6195 }
6196 
6197 /*@
6198   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6199 
6200   Collective on dm
6201 
6202   Input Parameters:
6203 + dm - the `DM`
6204 - dim - the dimension
6205 
6206   Output Parameters:
6207 + pStart - The first point of the given dimension
6208 - pEnd - The first point following points of the given dimension
6209 
6210   Note:
6211   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6212   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6213   then the interval is empty.
6214 
6215   Level: intermediate
6216 
6217 .seealso: `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6218 @*/
6219 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6220 {
6221   PetscInt d;
6222 
6223   PetscFunctionBegin;
6224   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6225   PetscCall(DMGetDimension(dm, &d));
6226   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6227   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6228   PetscFunctionReturn(0);
6229 }
6230 
6231 /*@
6232   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6233 
6234   Collective on dm
6235 
6236   Input Parameter:
6237 . dm - The original `DM`
6238 
6239   Output Parameter:
6240 . odm - The `DM` which provides the layout for output
6241 
6242   Level: intermediate
6243 
6244   Note:
6245   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6246   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6247   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6248 
6249 .seealso: `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6250 @*/
6251 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6252 {
6253   PetscSection section;
6254   PetscBool    hasConstraints, ghasConstraints;
6255 
6256   PetscFunctionBegin;
6257   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6258   PetscValidPointer(odm, 2);
6259   PetscCall(DMGetLocalSection(dm, &section));
6260   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6261   PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6262   if (!ghasConstraints) {
6263     *odm = dm;
6264     PetscFunctionReturn(0);
6265   }
6266   if (!dm->dmBC) {
6267     PetscSection newSection, gsection;
6268     PetscSF      sf;
6269 
6270     PetscCall(DMClone(dm, &dm->dmBC));
6271     PetscCall(DMCopyDisc(dm, dm->dmBC));
6272     PetscCall(PetscSectionClone(section, &newSection));
6273     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6274     PetscCall(PetscSectionDestroy(&newSection));
6275     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6276     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
6277     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6278     PetscCall(PetscSectionDestroy(&gsection));
6279   }
6280   *odm = dm->dmBC;
6281   PetscFunctionReturn(0);
6282 }
6283 
6284 /*@
6285   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6286 
6287   Input Parameter:
6288 . dm - The original `DM`
6289 
6290   Output Parameters:
6291 + num - The output sequence number
6292 - val - The output sequence value
6293 
6294   Level: intermediate
6295 
6296   Note:
6297   This is intended for output that should appear in sequence, for instance
6298   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6299 
6300   Developer Note:
6301   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6302   not directly related to the `DM`.
6303 
6304 .seealso: `VecView()`
6305 @*/
6306 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6307 {
6308   PetscFunctionBegin;
6309   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6310   if (num) {
6311     PetscValidIntPointer(num, 2);
6312     *num = dm->outputSequenceNum;
6313   }
6314   if (val) {
6315     PetscValidRealPointer(val, 3);
6316     *val = dm->outputSequenceVal;
6317   }
6318   PetscFunctionReturn(0);
6319 }
6320 
6321 /*@
6322   DMSetOutputSequenceNumber - Set the sequence number/value for output
6323 
6324   Input Parameters:
6325 + dm - The original `DM`
6326 . num - The output sequence number
6327 - val - The output sequence value
6328 
6329   Level: intermediate
6330 
6331   Note:
6332   This is intended for output that should appear in sequence, for instance
6333   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6334 
6335 .seealso: `VecView()`
6336 @*/
6337 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6338 {
6339   PetscFunctionBegin;
6340   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6341   dm->outputSequenceNum = num;
6342   dm->outputSequenceVal = val;
6343   PetscFunctionReturn(0);
6344 }
6345 
6346 /*@C
6347  DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6348 
6349   Input Parameters:
6350 + dm   - The original `DM`
6351 . name - The sequence name
6352 - num  - The output sequence number
6353 
6354   Output Parameter:
6355 . val  - The output sequence value
6356 
6357   Level: intermediate
6358 
6359   Note:
6360   This is intended for output that should appear in sequence, for instance
6361   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6362 
6363   Developer Note:
6364   It is unclear at the user API level why a `DM` is needed as input
6365 
6366 .seealso: `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6367 @*/
6368 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6369 {
6370   PetscBool ishdf5;
6371 
6372   PetscFunctionBegin;
6373   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6374   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6375   PetscValidRealPointer(val, 5);
6376   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6377   if (ishdf5) {
6378 #if defined(PETSC_HAVE_HDF5)
6379     PetscScalar value;
6380 
6381     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6382     *val = PetscRealPart(value);
6383 #endif
6384   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6385   PetscFunctionReturn(0);
6386 }
6387 
6388 /*@
6389   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6390 
6391   Not collective
6392 
6393   Input Parameter:
6394 . dm - The `DM`
6395 
6396   Output Parameter:
6397 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6398 
6399   Level: beginner
6400 
6401 .seealso: `DMSetUseNatural()`, `DMCreate()`
6402 @*/
6403 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6404 {
6405   PetscFunctionBegin;
6406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6407   PetscValidBoolPointer(useNatural, 2);
6408   *useNatural = dm->useNatural;
6409   PetscFunctionReturn(0);
6410 }
6411 
6412 /*@
6413   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6414 
6415   Collective on dm
6416 
6417   Input Parameters:
6418  + dm - The `DM`
6419 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6420 
6421   Note:
6422   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6423 
6424   Level: beginner
6425 
6426 .seealso: `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6427 @*/
6428 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6429 {
6430   PetscFunctionBegin;
6431   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6432   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6433   dm->useNatural = useNatural;
6434   PetscFunctionReturn(0);
6435 }
6436 
6437 /*@C
6438   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6439 
6440   Not Collective
6441 
6442   Input Parameters:
6443 + dm   - The `DM` object
6444 - name - The label name
6445 
6446   Level: intermediate
6447 
6448 .seealso: `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6449 @*/
6450 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6451 {
6452   PetscBool flg;
6453   DMLabel   label;
6454 
6455   PetscFunctionBegin;
6456   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6457   PetscValidCharPointer(name, 2);
6458   PetscCall(DMHasLabel(dm, name, &flg));
6459   if (!flg) {
6460     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6461     PetscCall(DMAddLabel(dm, label));
6462     PetscCall(DMLabelDestroy(&label));
6463   }
6464   PetscFunctionReturn(0);
6465 }
6466 
6467 /*@C
6468   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6469 
6470   Not Collective
6471 
6472   Input Parameters:
6473 + dm   - The `DM` object
6474 . l    - The index for the label
6475 - name - The label name
6476 
6477   Level: intermediate
6478 
6479 .seealso: `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6480 @*/
6481 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6482 {
6483   DMLabelLink orig, prev = NULL;
6484   DMLabel     label;
6485   PetscInt    Nl, m;
6486   PetscBool   flg, match;
6487   const char *lname;
6488 
6489   PetscFunctionBegin;
6490   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6491   PetscValidCharPointer(name, 3);
6492   PetscCall(DMHasLabel(dm, name, &flg));
6493   if (!flg) {
6494     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6495     PetscCall(DMAddLabel(dm, label));
6496     PetscCall(DMLabelDestroy(&label));
6497   }
6498   PetscCall(DMGetNumLabels(dm, &Nl));
6499   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6500   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6501     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6502     PetscCall(PetscStrcmp(name, lname, &match));
6503     if (match) break;
6504   }
6505   if (m == l) PetscFunctionReturn(0);
6506   if (!m) dm->labels = orig->next;
6507   else prev->next = orig->next;
6508   if (!l) {
6509     orig->next = dm->labels;
6510     dm->labels = orig;
6511   } else {
6512     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next)
6513       ;
6514     orig->next = prev->next;
6515     prev->next = orig;
6516   }
6517   PetscFunctionReturn(0);
6518 }
6519 
6520 /*@C
6521   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6522 
6523   Not Collective
6524 
6525   Input Parameters:
6526 + dm   - The `DM` object
6527 . name - The label name
6528 - point - The mesh point
6529 
6530   Output Parameter:
6531 . value - The label value for this point, or -1 if the point is not in the label
6532 
6533   Level: beginner
6534 
6535 .seealso: `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6536 @*/
6537 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6538 {
6539   DMLabel label;
6540 
6541   PetscFunctionBegin;
6542   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6543   PetscValidCharPointer(name, 2);
6544   PetscCall(DMGetLabel(dm, name, &label));
6545   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6546   PetscCall(DMLabelGetValue(label, point, value));
6547   PetscFunctionReturn(0);
6548 }
6549 
6550 /*@C
6551   DMSetLabelValue - Add a point to a `DMLabel` with given value
6552 
6553   Not Collective
6554 
6555   Input Parameters:
6556 + dm   - The `DM` object
6557 . name - The label name
6558 . point - The mesh point
6559 - value - The label value for this point
6560 
6561   Output Parameter:
6562 
6563   Level: beginner
6564 
6565 .seealso: `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6566 @*/
6567 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6568 {
6569   DMLabel label;
6570 
6571   PetscFunctionBegin;
6572   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6573   PetscValidCharPointer(name, 2);
6574   PetscCall(DMGetLabel(dm, name, &label));
6575   if (!label) {
6576     PetscCall(DMCreateLabel(dm, name));
6577     PetscCall(DMGetLabel(dm, name, &label));
6578   }
6579   PetscCall(DMLabelSetValue(label, point, value));
6580   PetscFunctionReturn(0);
6581 }
6582 
6583 /*@C
6584   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6585 
6586   Not Collective
6587 
6588   Input Parameters:
6589 + dm   - The `DM` object
6590 . name - The label name
6591 . point - The mesh point
6592 - value - The label value for this point
6593 
6594   Level: beginner
6595 
6596 .seealso: `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6597 @*/
6598 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6599 {
6600   DMLabel label;
6601 
6602   PetscFunctionBegin;
6603   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6604   PetscValidCharPointer(name, 2);
6605   PetscCall(DMGetLabel(dm, name, &label));
6606   if (!label) PetscFunctionReturn(0);
6607   PetscCall(DMLabelClearValue(label, point, value));
6608   PetscFunctionReturn(0);
6609 }
6610 
6611 /*@C
6612   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6613 
6614   Not Collective
6615 
6616   Input Parameters:
6617 + dm   - The `DM` object
6618 - name - The label name
6619 
6620   Output Parameter:
6621 . size - The number of different integer ids, or 0 if the label does not exist
6622 
6623   Level: beginner
6624 
6625   Developer Note:
6626   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6627 
6628 .seealso: `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6629 @*/
6630 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6631 {
6632   DMLabel label;
6633 
6634   PetscFunctionBegin;
6635   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6636   PetscValidCharPointer(name, 2);
6637   PetscValidIntPointer(size, 3);
6638   PetscCall(DMGetLabel(dm, name, &label));
6639   *size = 0;
6640   if (!label) PetscFunctionReturn(0);
6641   PetscCall(DMLabelGetNumValues(label, size));
6642   PetscFunctionReturn(0);
6643 }
6644 
6645 /*@C
6646   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6647 
6648   Not Collective
6649 
6650   Input Parameters:
6651 + mesh - The `DM` object
6652 - name - The label name
6653 
6654   Output Parameter:
6655 . ids - The integer ids, or NULL if the label does not exist
6656 
6657   Level: beginner
6658 
6659 .seealso: `DMLabelGetValueIS()`, `DMGetLabelSize()`
6660 @*/
6661 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6662 {
6663   DMLabel label;
6664 
6665   PetscFunctionBegin;
6666   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6667   PetscValidCharPointer(name, 2);
6668   PetscValidPointer(ids, 3);
6669   PetscCall(DMGetLabel(dm, name, &label));
6670   *ids = NULL;
6671   if (label) {
6672     PetscCall(DMLabelGetValueIS(label, ids));
6673   } else {
6674     /* returning an empty IS */
6675     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6676   }
6677   PetscFunctionReturn(0);
6678 }
6679 
6680 /*@C
6681   DMGetStratumSize - Get the number of points in a label stratum
6682 
6683   Not Collective
6684 
6685   Input Parameters:
6686 + dm - The `DM` object
6687 . name - The label name
6688 - value - The stratum value
6689 
6690   Output Parameter:
6691 . size - The number of points, also called the stratum size
6692 
6693   Level: beginner
6694 
6695 .seealso: `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6696 @*/
6697 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6698 {
6699   DMLabel label;
6700 
6701   PetscFunctionBegin;
6702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6703   PetscValidCharPointer(name, 2);
6704   PetscValidIntPointer(size, 4);
6705   PetscCall(DMGetLabel(dm, name, &label));
6706   *size = 0;
6707   if (!label) PetscFunctionReturn(0);
6708   PetscCall(DMLabelGetStratumSize(label, value, size));
6709   PetscFunctionReturn(0);
6710 }
6711 
6712 /*@C
6713   DMGetStratumIS - Get the points in a label stratum
6714 
6715   Not Collective
6716 
6717   Input Parameters:
6718 + dm - The `DM` object
6719 . name - The label name
6720 - value - The stratum value
6721 
6722   Output Parameter:
6723 . points - The stratum points, or NULL if the label does not exist or does not have that value
6724 
6725   Level: beginner
6726 
6727 .seealso: `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6728 @*/
6729 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6730 {
6731   DMLabel label;
6732 
6733   PetscFunctionBegin;
6734   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6735   PetscValidCharPointer(name, 2);
6736   PetscValidPointer(points, 4);
6737   PetscCall(DMGetLabel(dm, name, &label));
6738   *points = NULL;
6739   if (!label) PetscFunctionReturn(0);
6740   PetscCall(DMLabelGetStratumIS(label, value, points));
6741   PetscFunctionReturn(0);
6742 }
6743 
6744 /*@C
6745   DMSetStratumIS - Set the points in a label stratum
6746 
6747   Not Collective
6748 
6749   Input Parameters:
6750 + dm - The `DM` object
6751 . name - The label name
6752 . value - The stratum value
6753 - points - The stratum points
6754 
6755   Level: beginner
6756 
6757 .seealso: `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
6758 @*/
6759 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6760 {
6761   DMLabel label;
6762 
6763   PetscFunctionBegin;
6764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6765   PetscValidCharPointer(name, 2);
6766   PetscValidPointer(points, 4);
6767   PetscCall(DMGetLabel(dm, name, &label));
6768   if (!label) PetscFunctionReturn(0);
6769   PetscCall(DMLabelSetStratumIS(label, value, points));
6770   PetscFunctionReturn(0);
6771 }
6772 
6773 /*@C
6774   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
6775 
6776   Not Collective
6777 
6778   Input Parameters:
6779 + dm   - The `DM` object
6780 . name - The label name
6781 - value - The label value for this point
6782 
6783   Output Parameter:
6784 
6785   Level: beginner
6786 
6787 .seealso: `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6788 @*/
6789 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6790 {
6791   DMLabel label;
6792 
6793   PetscFunctionBegin;
6794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6795   PetscValidCharPointer(name, 2);
6796   PetscCall(DMGetLabel(dm, name, &label));
6797   if (!label) PetscFunctionReturn(0);
6798   PetscCall(DMLabelClearStratum(label, value));
6799   PetscFunctionReturn(0);
6800 }
6801 
6802 /*@
6803   DMGetNumLabels - Return the number of labels defined by on the `DM`
6804 
6805   Not Collective
6806 
6807   Input Parameter:
6808 . dm   - The `DM` object
6809 
6810   Output Parameter:
6811 . numLabels - the number of Labels
6812 
6813   Level: intermediate
6814 
6815 .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6816 @*/
6817 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6818 {
6819   DMLabelLink next = dm->labels;
6820   PetscInt    n    = 0;
6821 
6822   PetscFunctionBegin;
6823   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6824   PetscValidIntPointer(numLabels, 2);
6825   while (next) {
6826     ++n;
6827     next = next->next;
6828   }
6829   *numLabels = n;
6830   PetscFunctionReturn(0);
6831 }
6832 
6833 /*@C
6834   DMGetLabelName - Return the name of nth label
6835 
6836   Not Collective
6837 
6838   Input Parameters:
6839 + dm - The `DM` object
6840 - n  - the label number
6841 
6842   Output Parameter:
6843 . name - the label name
6844 
6845   Level: intermediate
6846 
6847   Developer Note:
6848   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
6849 
6850 .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6851 @*/
6852 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6853 {
6854   DMLabelLink next = dm->labels;
6855   PetscInt    l    = 0;
6856 
6857   PetscFunctionBegin;
6858   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6859   PetscValidPointer(name, 3);
6860   while (next) {
6861     if (l == n) {
6862       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
6863       PetscFunctionReturn(0);
6864     }
6865     ++l;
6866     next = next->next;
6867   }
6868   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6869 }
6870 
6871 /*@C
6872   DMHasLabel - Determine whether the `DM` has a label of a given name
6873 
6874   Not Collective
6875 
6876   Input Parameters:
6877 + dm   - The `DM` object
6878 - name - The label name
6879 
6880   Output Parameter:
6881 . hasLabel - `PETSC_TRUE` if the label is present
6882 
6883   Level: intermediate
6884 
6885 .seealso: `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6886 @*/
6887 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6888 {
6889   DMLabelLink next = dm->labels;
6890   const char *lname;
6891 
6892   PetscFunctionBegin;
6893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6894   PetscValidCharPointer(name, 2);
6895   PetscValidBoolPointer(hasLabel, 3);
6896   *hasLabel = PETSC_FALSE;
6897   while (next) {
6898     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
6899     PetscCall(PetscStrcmp(name, lname, hasLabel));
6900     if (*hasLabel) break;
6901     next = next->next;
6902   }
6903   PetscFunctionReturn(0);
6904 }
6905 
6906 /*@C
6907   DMGetLabel - Return the label of a given name, or NULL, from a `DM`
6908 
6909   Not Collective
6910 
6911   Input Parameters:
6912 + dm   - The `DM` object
6913 - name - The label name
6914 
6915   Output Parameter:
6916 . label - The `DMLabel`, or NULL if the label is absent
6917 
6918   Default labels in a `DMPLEX`:
6919 +   "depth"       - Holds the depth (co-dimension) of each mesh point
6920 .   "celltype"    - Holds the topological type of each cell
6921 .   "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6922 .   "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
6923 .   "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
6924 -  "Vertex Sets" - Mirrors the vertex sets defined by GMsh
6925 
6926   Level: intermediate
6927 
6928 .seealso: `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6929 @*/
6930 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6931 {
6932   DMLabelLink next = dm->labels;
6933   PetscBool   hasLabel;
6934   const char *lname;
6935 
6936   PetscFunctionBegin;
6937   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6938   PetscValidCharPointer(name, 2);
6939   PetscValidPointer(label, 3);
6940   *label = NULL;
6941   while (next) {
6942     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
6943     PetscCall(PetscStrcmp(name, lname, &hasLabel));
6944     if (hasLabel) {
6945       *label = next->label;
6946       break;
6947     }
6948     next = next->next;
6949   }
6950   PetscFunctionReturn(0);
6951 }
6952 
6953 /*@C
6954   DMGetLabelByNum - Return the nth label on a `DM`
6955 
6956   Not Collective
6957 
6958   Input Parameters:
6959 + dm - The `DM` object
6960 - n  - the label number
6961 
6962   Output Parameter:
6963 . label - the label
6964 
6965   Level: intermediate
6966 
6967 .seealso: `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6968 @*/
6969 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
6970 {
6971   DMLabelLink next = dm->labels;
6972   PetscInt    l    = 0;
6973 
6974   PetscFunctionBegin;
6975   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6976   PetscValidPointer(label, 3);
6977   while (next) {
6978     if (l == n) {
6979       *label = next->label;
6980       PetscFunctionReturn(0);
6981     }
6982     ++l;
6983     next = next->next;
6984   }
6985   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6986 }
6987 
6988 /*@C
6989   DMAddLabel - Add the label to this `DM`
6990 
6991   Not Collective
6992 
6993   Input Parameters:
6994 + dm   - The `DM` object
6995 - label - The `DMLabel`
6996 
6997   Level: developer
6998 
6999 .seealso: `DMLabel`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7000 @*/
7001 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7002 {
7003   DMLabelLink l, *p, tmpLabel;
7004   PetscBool   hasLabel;
7005   const char *lname;
7006   PetscBool   flg;
7007 
7008   PetscFunctionBegin;
7009   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7010   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7011   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7012   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7013   PetscCall(PetscCalloc1(1, &tmpLabel));
7014   tmpLabel->label  = label;
7015   tmpLabel->output = PETSC_TRUE;
7016   for (p = &dm->labels; (l = *p); p = &l->next) { }
7017   *p = tmpLabel;
7018   PetscCall(PetscObjectReference((PetscObject)label));
7019   PetscCall(PetscStrcmp(lname, "depth", &flg));
7020   if (flg) dm->depthLabel = label;
7021   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7022   if (flg) dm->celltypeLabel = label;
7023   PetscFunctionReturn(0);
7024 }
7025 
7026 /*@C
7027   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7028 
7029   Not Collective
7030 
7031   Input Parameters:
7032 + dm    - The `DM` object
7033 - label - The `DMLabel`, having the same name, to substitute
7034 
7035   Default labels in a `DMPLEX`:
7036 +  "depth"       - Holds the depth (co-dimension) of each mesh point
7037 .  "celltype"    - Holds the topological type of each cell
7038 .  "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7039 .  "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7040 .  "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7041 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7042 
7043   Level: intermediate
7044 
7045 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7046 @*/
7047 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7048 {
7049   DMLabelLink next = dm->labels;
7050   PetscBool   hasLabel, flg;
7051   const char *name, *lname;
7052 
7053   PetscFunctionBegin;
7054   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7055   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7056   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7057   while (next) {
7058     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7059     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7060     if (hasLabel) {
7061       PetscCall(PetscObjectReference((PetscObject)label));
7062       PetscCall(PetscStrcmp(lname, "depth", &flg));
7063       if (flg) dm->depthLabel = label;
7064       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7065       if (flg) dm->celltypeLabel = label;
7066       PetscCall(DMLabelDestroy(&next->label));
7067       next->label = label;
7068       break;
7069     }
7070     next = next->next;
7071   }
7072   PetscFunctionReturn(0);
7073 }
7074 
7075 /*@C
7076   DMRemoveLabel - Remove the label given by name from this `DM`
7077 
7078   Not Collective
7079 
7080   Input Parameters:
7081 + dm   - The `DM` object
7082 - name - The label name
7083 
7084   Output Parameter:
7085 . label - The `DMLabel`, or NULL if the label is absent. Pass in NULL to call `DMLabelDestroy()` on the label, otherwise the
7086           caller is responsible for calling `DMLabelDestroy()`.
7087 
7088   Level: developer
7089 
7090 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7091 @*/
7092 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7093 {
7094   DMLabelLink link, *pnext;
7095   PetscBool   hasLabel;
7096   const char *lname;
7097 
7098   PetscFunctionBegin;
7099   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7100   PetscValidCharPointer(name, 2);
7101   if (label) {
7102     PetscValidPointer(label, 3);
7103     *label = NULL;
7104   }
7105   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7106     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7107     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7108     if (hasLabel) {
7109       *pnext = link->next; /* Remove from list */
7110       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7111       if (hasLabel) dm->depthLabel = NULL;
7112       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7113       if (hasLabel) dm->celltypeLabel = NULL;
7114       if (label) *label = link->label;
7115       else PetscCall(DMLabelDestroy(&link->label));
7116       PetscCall(PetscFree(link));
7117       break;
7118     }
7119   }
7120   PetscFunctionReturn(0);
7121 }
7122 
7123 /*@
7124   DMRemoveLabelBySelf - Remove the label from this `DM`
7125 
7126   Not Collective
7127 
7128   Input Parameters:
7129 + dm   - The `DM` object
7130 . label - The `DMLabel` to be removed from the `DM`
7131 - failNotFound - Should it fail if the label is not found in the DM?
7132 
7133   Level: developer
7134 
7135   Note:
7136   Only exactly the same instance is removed if found, name match is ignored.
7137   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7138   *label nullified.
7139 
7140 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7141 @*/
7142 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7143 {
7144   DMLabelLink link, *pnext;
7145   PetscBool   hasLabel = PETSC_FALSE;
7146 
7147   PetscFunctionBegin;
7148   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7149   PetscValidPointer(label, 2);
7150   if (!*label && !failNotFound) PetscFunctionReturn(0);
7151   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7152   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7153   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7154     if (*label == link->label) {
7155       hasLabel = PETSC_TRUE;
7156       *pnext   = link->next; /* Remove from list */
7157       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7158       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7159       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7160       PetscCall(DMLabelDestroy(&link->label));
7161       PetscCall(PetscFree(link));
7162       break;
7163     }
7164   }
7165   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7166   PetscFunctionReturn(0);
7167 }
7168 
7169 /*@C
7170   DMGetLabelOutput - Get the output flag for a given label
7171 
7172   Not Collective
7173 
7174   Input Parameters:
7175 + dm   - The `DM` object
7176 - name - The label name
7177 
7178   Output Parameter:
7179 . output - The flag for output
7180 
7181   Level: developer
7182 
7183 .seealso: `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7184 @*/
7185 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7186 {
7187   DMLabelLink next = dm->labels;
7188   const char *lname;
7189 
7190   PetscFunctionBegin;
7191   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7192   PetscValidCharPointer(name, 2);
7193   PetscValidBoolPointer(output, 3);
7194   while (next) {
7195     PetscBool flg;
7196 
7197     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7198     PetscCall(PetscStrcmp(name, lname, &flg));
7199     if (flg) {
7200       *output = next->output;
7201       PetscFunctionReturn(0);
7202     }
7203     next = next->next;
7204   }
7205   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7206 }
7207 
7208 /*@C
7209   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7210 
7211   Not Collective
7212 
7213   Input Parameters:
7214 + dm     - The `DM` object
7215 . name   - The label name
7216 - output - `PETSC_TRUE` to save the label to the viewer
7217 
7218   Level: developer
7219 
7220 .seealso: `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7221 @*/
7222 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7223 {
7224   DMLabelLink next = dm->labels;
7225   const char *lname;
7226 
7227   PetscFunctionBegin;
7228   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7229   PetscValidCharPointer(name, 2);
7230   while (next) {
7231     PetscBool flg;
7232 
7233     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7234     PetscCall(PetscStrcmp(name, lname, &flg));
7235     if (flg) {
7236       next->output = output;
7237       PetscFunctionReturn(0);
7238     }
7239     next = next->next;
7240   }
7241   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7242 }
7243 
7244 /*@
7245   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7246 
7247   Collective on dmA
7248 
7249   Input Parameters:
7250 + dmA - The `DM` object with initial labels
7251 . dmB - The `DM` object to which labels are copied
7252 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7253 . all  - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7254 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7255 
7256   Level: intermediate
7257 
7258   Note:
7259   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7260 
7261 .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7262 @*/
7263 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7264 {
7265   DMLabel     label, labelNew, labelOld;
7266   const char *name;
7267   PetscBool   flg;
7268   DMLabelLink link;
7269 
7270   PetscFunctionBegin;
7271   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7272   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7273   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7274   PetscValidLogicalCollectiveBool(dmA, all, 4);
7275   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7276   if (dmA == dmB) PetscFunctionReturn(0);
7277   for (link = dmA->labels; link; link = link->next) {
7278     label = link->label;
7279     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7280     if (!all) {
7281       PetscCall(PetscStrcmp(name, "depth", &flg));
7282       if (flg) continue;
7283       PetscCall(PetscStrcmp(name, "dim", &flg));
7284       if (flg) continue;
7285       PetscCall(PetscStrcmp(name, "celltype", &flg));
7286       if (flg) continue;
7287     }
7288     PetscCall(DMGetLabel(dmB, name, &labelOld));
7289     if (labelOld) {
7290       switch (emode) {
7291       case DM_COPY_LABELS_KEEP:
7292         continue;
7293       case DM_COPY_LABELS_REPLACE:
7294         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7295         break;
7296       case DM_COPY_LABELS_FAIL:
7297         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7298       default:
7299         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7300       }
7301     }
7302     if (mode == PETSC_COPY_VALUES) {
7303       PetscCall(DMLabelDuplicate(label, &labelNew));
7304     } else {
7305       labelNew = label;
7306     }
7307     PetscCall(DMAddLabel(dmB, labelNew));
7308     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7309   }
7310   PetscFunctionReturn(0);
7311 }
7312 
7313 /*@C
7314   DMCompareLabels - Compare labels of two `DMPLEX` meshes
7315 
7316   Collective
7317 
7318   Input Parameters:
7319 + dm0 - First `DM` object
7320 - dm1 - Second `DM` object
7321 
7322   Output Parameters
7323 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7324 - message - (Optional) Message describing the difference, or NULL if there is no difference
7325 
7326   Level: intermediate
7327 
7328   Notes:
7329   The output flag equal will be the same on all processes.
7330 
7331   If equal is passed as NULL and difference is found, an error is thrown on all processes.
7332 
7333   Make sure to pass equal is NULL on all processes or none of them.
7334 
7335   The output message is set independently on each rank.
7336 
7337   message must be freed with `PetscFree()`
7338 
7339   If message is passed as NULL and a difference is found, the difference description is printed to stderr in synchronized manner.
7340 
7341   Make sure to pass message as NULL on all processes or no processes.
7342 
7343   Labels are matched by name. If the number of labels and their names are equal,
7344   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7345 
7346   Fortran Note:
7347   This function is not available from Fortran.
7348 
7349 .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7350 @*/
7351 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7352 {
7353   PetscInt    n, i;
7354   char        msg[PETSC_MAX_PATH_LEN] = "";
7355   PetscBool   eq;
7356   MPI_Comm    comm;
7357   PetscMPIInt rank;
7358 
7359   PetscFunctionBegin;
7360   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7361   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7362   PetscCheckSameComm(dm0, 1, dm1, 2);
7363   if (equal) PetscValidBoolPointer(equal, 3);
7364   if (message) PetscValidPointer(message, 4);
7365   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7366   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7367   {
7368     PetscInt n1;
7369 
7370     PetscCall(DMGetNumLabels(dm0, &n));
7371     PetscCall(DMGetNumLabels(dm1, &n1));
7372     eq = (PetscBool)(n == n1);
7373     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7374     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7375     if (!eq) goto finish;
7376   }
7377   for (i = 0; i < n; i++) {
7378     DMLabel     l0, l1;
7379     const char *name;
7380     char       *msgInner;
7381 
7382     /* Ignore label order */
7383     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7384     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7385     PetscCall(DMGetLabel(dm1, name, &l1));
7386     if (!l1) {
7387       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7388       eq = PETSC_FALSE;
7389       break;
7390     }
7391     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7392     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7393     PetscCall(PetscFree(msgInner));
7394     if (!eq) break;
7395   }
7396   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7397 finish:
7398   /* If message output arg not set, print to stderr */
7399   if (message) {
7400     *message = NULL;
7401     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7402   } else {
7403     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7404     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7405   }
7406   /* If same output arg not ser and labels are not equal, throw error */
7407   if (equal) *equal = eq;
7408   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7409   PetscFunctionReturn(0);
7410 }
7411 
7412 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7413 {
7414   PetscFunctionBegin;
7415   PetscValidPointer(label, 2);
7416   if (!*label) {
7417     PetscCall(DMCreateLabel(dm, name));
7418     PetscCall(DMGetLabel(dm, name, label));
7419   }
7420   PetscCall(DMLabelSetValue(*label, point, value));
7421   PetscFunctionReturn(0);
7422 }
7423 
7424 /*
7425   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7426   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7427   (label, id) pair in the DM.
7428 
7429   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7430   each label.
7431 */
7432 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7433 {
7434   DMUniversalLabel ul;
7435   PetscBool       *active;
7436   PetscInt         pStart, pEnd, p, Nl, l, m;
7437 
7438   PetscFunctionBegin;
7439   PetscCall(PetscMalloc1(1, &ul));
7440   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7441   PetscCall(DMGetNumLabels(dm, &Nl));
7442   PetscCall(PetscCalloc1(Nl, &active));
7443   ul->Nl = 0;
7444   for (l = 0; l < Nl; ++l) {
7445     PetscBool   isdepth, iscelltype;
7446     const char *name;
7447 
7448     PetscCall(DMGetLabelName(dm, l, &name));
7449     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7450     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7451     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7452     if (active[l]) ++ul->Nl;
7453   }
7454   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7455   ul->Nv = 0;
7456   for (l = 0, m = 0; l < Nl; ++l) {
7457     DMLabel     label;
7458     PetscInt    nv;
7459     const char *name;
7460 
7461     if (!active[l]) continue;
7462     PetscCall(DMGetLabelName(dm, l, &name));
7463     PetscCall(DMGetLabelByNum(dm, l, &label));
7464     PetscCall(DMLabelGetNumValues(label, &nv));
7465     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7466     ul->indices[m] = l;
7467     ul->Nv += nv;
7468     ul->offsets[m + 1] = nv;
7469     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7470     ++m;
7471   }
7472   for (l = 1; l <= ul->Nl; ++l) {
7473     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7474     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7475   }
7476   for (l = 0; l < ul->Nl; ++l) {
7477     PetscInt b;
7478 
7479     ul->masks[l] = 0;
7480     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7481   }
7482   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7483   for (l = 0, m = 0; l < Nl; ++l) {
7484     DMLabel         label;
7485     IS              valueIS;
7486     const PetscInt *varr;
7487     PetscInt        nv, v;
7488 
7489     if (!active[l]) continue;
7490     PetscCall(DMGetLabelByNum(dm, l, &label));
7491     PetscCall(DMLabelGetNumValues(label, &nv));
7492     PetscCall(DMLabelGetValueIS(label, &valueIS));
7493     PetscCall(ISGetIndices(valueIS, &varr));
7494     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7495     PetscCall(ISRestoreIndices(valueIS, &varr));
7496     PetscCall(ISDestroy(&valueIS));
7497     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7498     ++m;
7499   }
7500   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7501   for (p = pStart; p < pEnd; ++p) {
7502     PetscInt  uval   = 0;
7503     PetscBool marked = PETSC_FALSE;
7504 
7505     for (l = 0, m = 0; l < Nl; ++l) {
7506       DMLabel  label;
7507       PetscInt val, defval, loc, nv;
7508 
7509       if (!active[l]) continue;
7510       PetscCall(DMGetLabelByNum(dm, l, &label));
7511       PetscCall(DMLabelGetValue(label, p, &val));
7512       PetscCall(DMLabelGetDefaultValue(label, &defval));
7513       if (val == defval) {
7514         ++m;
7515         continue;
7516       }
7517       nv     = ul->offsets[m + 1] - ul->offsets[m];
7518       marked = PETSC_TRUE;
7519       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7520       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7521       uval += (loc + 1) << ul->bits[m];
7522       ++m;
7523     }
7524     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7525   }
7526   PetscCall(PetscFree(active));
7527   *universal = ul;
7528   PetscFunctionReturn(0);
7529 }
7530 
7531 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7532 {
7533   PetscInt l;
7534 
7535   PetscFunctionBegin;
7536   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7537   PetscCall(DMLabelDestroy(&(*universal)->label));
7538   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7539   PetscCall(PetscFree((*universal)->values));
7540   PetscCall(PetscFree(*universal));
7541   *universal = NULL;
7542   PetscFunctionReturn(0);
7543 }
7544 
7545 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7546 {
7547   PetscFunctionBegin;
7548   PetscValidPointer(ulabel, 2);
7549   *ulabel = ul->label;
7550   PetscFunctionReturn(0);
7551 }
7552 
7553 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7554 {
7555   PetscInt Nl = ul->Nl, l;
7556 
7557   PetscFunctionBegin;
7558   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7559   for (l = 0; l < Nl; ++l) {
7560     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7561     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7562   }
7563   if (preserveOrder) {
7564     for (l = 0; l < ul->Nl; ++l) {
7565       const char *name;
7566       PetscBool   match;
7567 
7568       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7569       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7570       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]);
7571     }
7572   }
7573   PetscFunctionReturn(0);
7574 }
7575 
7576 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7577 {
7578   PetscInt l;
7579 
7580   PetscFunctionBegin;
7581   for (l = 0; l < ul->Nl; ++l) {
7582     DMLabel  label;
7583     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7584 
7585     if (lval) {
7586       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7587       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7588       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7589     }
7590   }
7591   PetscFunctionReturn(0);
7592 }
7593 
7594 /*@
7595   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7596 
7597   Not collective
7598 
7599   Input Parameter:
7600 . dm - The `DM` object
7601 
7602   Output Parameter:
7603 . cdm - The coarse `DM`
7604 
7605   Level: intermediate
7606 
7607 .seealso: `DMSetCoarseDM()`, `DMCoarsen()`
7608 @*/
7609 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7610 {
7611   PetscFunctionBegin;
7612   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7613   PetscValidPointer(cdm, 2);
7614   *cdm = dm->coarseMesh;
7615   PetscFunctionReturn(0);
7616 }
7617 
7618 /*@
7619   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7620 
7621   Input Parameters:
7622 + dm - The `DM` object
7623 - cdm - The coarse `DM`
7624 
7625   Level: intermediate
7626 
7627   Note:
7628   Normally this is set automatically by `DMRefine()`
7629 
7630 .seealso: `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7631 @*/
7632 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7633 {
7634   PetscFunctionBegin;
7635   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7636   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7637   if (dm == cdm) cdm = NULL;
7638   PetscCall(PetscObjectReference((PetscObject)cdm));
7639   PetscCall(DMDestroy(&dm->coarseMesh));
7640   dm->coarseMesh = cdm;
7641   PetscFunctionReturn(0);
7642 }
7643 
7644 /*@
7645   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7646 
7647   Input Parameter:
7648 . dm - The `DM` object
7649 
7650   Output Parameter:
7651 . fdm - The fine `DM`
7652 
7653   Level: intermediate
7654 
7655 .seealso: `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7656 @*/
7657 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7658 {
7659   PetscFunctionBegin;
7660   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7661   PetscValidPointer(fdm, 2);
7662   *fdm = dm->fineMesh;
7663   PetscFunctionReturn(0);
7664 }
7665 
7666 /*@
7667   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7668 
7669   Input Parameters:
7670 + dm - The `DM` object
7671 - fdm - The fine `DM`
7672 
7673   Level: developer
7674 
7675   Note:
7676   Normally this is set automatically by `DMCoarsen()`
7677 
7678 .seealso: `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7679 @*/
7680 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7681 {
7682   PetscFunctionBegin;
7683   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7684   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7685   if (dm == fdm) fdm = NULL;
7686   PetscCall(PetscObjectReference((PetscObject)fdm));
7687   PetscCall(DMDestroy(&dm->fineMesh));
7688   dm->fineMesh = fdm;
7689   PetscFunctionReturn(0);
7690 }
7691 
7692 /*@C
7693   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7694 
7695   Collective on dm
7696 
7697   Input Parameters:
7698 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7699 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7700 . name     - The BC name
7701 . label    - The label defining constrained points
7702 . Nv       - The number of `DMLabel` values for constrained points
7703 . values   - An array of values for constrained points
7704 . field    - The field to constrain
7705 . Nc       - The number of constrained field components (0 will constrain all fields)
7706 . comps    - An array of constrained component numbers
7707 . bcFunc   - A pointwise function giving boundary values
7708 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7709 - ctx      - An optional user context for bcFunc
7710 
7711   Output Parameter:
7712 . bd          - (Optional) Boundary number
7713 
7714   Options Database Keys:
7715 + -bc_<boundary name> <num> - Overrides the boundary ids
7716 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7717 
7718   Notes:
7719   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is:
7720 
7721 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
7722 
7723   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is:
7724 
7725 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7726 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7727 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7728 $        PetscReal time, const PetscReal x[], PetscScalar bcval[])
7729 
7730 + dim - the spatial dimension
7731 . Nf - the number of fields
7732 . uOff - the offset into u[] and u_t[] for each field
7733 . uOff_x - the offset into u_x[] for each field
7734 . u - each field evaluated at the current point
7735 . u_t - the time derivative of each field evaluated at the current point
7736 . u_x - the gradient of each field evaluated at the current point
7737 . aOff - the offset into a[] and a_t[] for each auxiliary field
7738 . aOff_x - the offset into a_x[] for each auxiliary field
7739 . a - each auxiliary field evaluated at the current point
7740 . a_t - the time derivative of each auxiliary field evaluated at the current point
7741 . a_x - the gradient of auxiliary each field evaluated at the current point
7742 . t - current time
7743 . x - coordinates of the current point
7744 . numConstants - number of constant parameters
7745 . constants - constant parameters
7746 - bcval - output values at the current point
7747 
7748   Level: intermediate
7749 
7750 .seealso: `DSGetBoundary()`, `PetscDSAddBoundary()`
7751 @*/
7752 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)
7753 {
7754   PetscDS ds;
7755 
7756   PetscFunctionBegin;
7757   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7758   PetscValidLogicalCollectiveEnum(dm, type, 2);
7759   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
7760   PetscValidLogicalCollectiveInt(dm, Nv, 5);
7761   PetscValidLogicalCollectiveInt(dm, field, 7);
7762   PetscValidLogicalCollectiveInt(dm, Nc, 8);
7763   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
7764   PetscCall(DMGetDS(dm, &ds));
7765   /* Complete label */
7766   if (label) {
7767     PetscObject  obj;
7768     PetscClassId id;
7769 
7770     PetscCall(DMGetField(dm, field, NULL, &obj));
7771     PetscCall(PetscObjectGetClassId(obj, &id));
7772     if (id == PETSCFE_CLASSID) {
7773       DM plex;
7774 
7775       PetscCall(DMConvert(dm, DMPLEX, &plex));
7776       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
7777       PetscCall(DMDestroy(&plex));
7778     }
7779   }
7780   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
7781   PetscFunctionReturn(0);
7782 }
7783 
7784 /* TODO Remove this since now the structures are the same */
7785 static PetscErrorCode DMPopulateBoundary(DM dm)
7786 {
7787   PetscDS     ds;
7788   DMBoundary *lastnext;
7789   DSBoundary  dsbound;
7790 
7791   PetscFunctionBegin;
7792   PetscCall(DMGetDS(dm, &ds));
7793   dsbound = ds->boundary;
7794   if (dm->boundary) {
7795     DMBoundary next = dm->boundary;
7796 
7797     /* quick check to see if the PetscDS has changed */
7798     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
7799     /* the PetscDS has changed: tear down and rebuild */
7800     while (next) {
7801       DMBoundary b = next;
7802 
7803       next = b->next;
7804       PetscCall(PetscFree(b));
7805     }
7806     dm->boundary = NULL;
7807   }
7808 
7809   lastnext = &(dm->boundary);
7810   while (dsbound) {
7811     DMBoundary dmbound;
7812 
7813     PetscCall(PetscNew(&dmbound));
7814     dmbound->dsboundary = dsbound;
7815     dmbound->label      = dsbound->label;
7816     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7817     *lastnext = dmbound;
7818     lastnext  = &(dmbound->next);
7819     dsbound   = dsbound->next;
7820   }
7821   PetscFunctionReturn(0);
7822 }
7823 
7824 /* TODO: missing manual page */
7825 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7826 {
7827   DMBoundary b;
7828 
7829   PetscFunctionBegin;
7830   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7831   PetscValidBoolPointer(isBd, 3);
7832   *isBd = PETSC_FALSE;
7833   PetscCall(DMPopulateBoundary(dm));
7834   b = dm->boundary;
7835   while (b && !(*isBd)) {
7836     DMLabel    label = b->label;
7837     DSBoundary dsb   = b->dsboundary;
7838     PetscInt   i;
7839 
7840     if (label) {
7841       for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
7842     }
7843     b = b->next;
7844   }
7845   PetscFunctionReturn(0);
7846 }
7847 
7848 /*@C
7849   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
7850 
7851   Collective on dm
7852 
7853   Input Parameters:
7854 + dm      - The `DM`
7855 . time    - The time
7856 . funcs   - The coordinate functions to evaluate, one per field
7857 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7858 - mode    - The insertion mode for values
7859 
7860   Output Parameter:
7861 . X - vector
7862 
7863    Calling sequence of func:
7864 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7865 
7866 +  dim - The spatial dimension
7867 .  time - The time at which to sample
7868 .  x   - The coordinates
7869 .  Nc  - The number of components
7870 .  u   - The output field values
7871 -  ctx - optional user-defined function context
7872 
7873   Level: developer
7874 
7875   Developer Notes:
7876   This API is specific to only particular usage of `DM`
7877 
7878   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7879 
7880 .seealso: `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7881 @*/
7882 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7883 {
7884   Vec localX;
7885 
7886   PetscFunctionBegin;
7887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7888   PetscCall(DMGetLocalVector(dm, &localX));
7889   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
7890   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
7891   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
7892   PetscCall(DMRestoreLocalVector(dm, &localX));
7893   PetscFunctionReturn(0);
7894 }
7895 
7896 /*@C
7897   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
7898 
7899   Not collective
7900 
7901   Input Parameters:
7902 + dm      - The `DM`
7903 . time    - The time
7904 . funcs   - The coordinate functions to evaluate, one per field
7905 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7906 - mode    - The insertion mode for values
7907 
7908   Output Parameter:
7909 . localX - vector
7910 
7911    Calling sequence of func:
7912 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7913 
7914 +  dim - The spatial dimension
7915 .  x   - The coordinates
7916 .  Nc  - The number of components
7917 .  u   - The output field values
7918 -  ctx - optional user-defined function context
7919 
7920   Level: developer
7921 
7922   Developer Notes:
7923   This API is specific to only particular usage of `DM`
7924 
7925   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7926 
7927 .seealso: `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7928 @*/
7929 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7930 {
7931   PetscFunctionBegin;
7932   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7933   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
7934   PetscCall((dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX));
7935   PetscFunctionReturn(0);
7936 }
7937 
7938 /*@C
7939   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.
7940 
7941   Collective on dm
7942 
7943   Input Parameters:
7944 + dm      - The `DM`
7945 . time    - The time
7946 . label   - The `DMLabel` selecting the portion of the mesh for projection
7947 . funcs   - The coordinate functions to evaluate, one per field
7948 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
7949 - mode    - The insertion mode for values
7950 
7951   Output Parameter:
7952 . X - vector
7953 
7954    Calling sequence of func:
7955 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7956 
7957 +  dim - The spatial dimension
7958 .  x   - The coordinates
7959 .  Nc  - The number of components
7960 .  u   - The output field values
7961 -  ctx - optional user-defined function context
7962 
7963   Level: developer
7964 
7965   Developer Notes:
7966   This API is specific to only particular usage of `DM`
7967 
7968   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7969 
7970 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
7971 @*/
7972 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)
7973 {
7974   Vec localX;
7975 
7976   PetscFunctionBegin;
7977   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7978   PetscCall(DMGetLocalVector(dm, &localX));
7979   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
7980   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
7981   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
7982   PetscCall(DMRestoreLocalVector(dm, &localX));
7983   PetscFunctionReturn(0);
7984 }
7985 
7986 /*@C
7987   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.
7988 
7989   Not collective
7990 
7991   Input Parameters:
7992 + dm      - The `DM`
7993 . time    - The time
7994 . label   - The `DMLabel` selecting the portion of the mesh for projection
7995 . funcs   - The coordinate functions to evaluate, one per field
7996 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7997 - mode    - The insertion mode for values
7998 
7999   Output Parameter:
8000 . localX - vector
8001 
8002    Calling sequence of func:
8003 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8004 
8005 +  dim - The spatial dimension
8006 .  x   - The coordinates
8007 .  Nc  - The number of components
8008 .  u   - The output field values
8009 -  ctx - optional user-defined function context
8010 
8011   Level: developer
8012 
8013   Developer Notes:
8014   This API is specific to only particular usage of `DM`
8015 
8016   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8017 
8018 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8019 @*/
8020 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)
8021 {
8022   PetscFunctionBegin;
8023   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8024   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8025   PetscCall((dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8026   PetscFunctionReturn(0);
8027 }
8028 
8029 /*@C
8030   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.
8031 
8032   Not collective
8033 
8034   Input Parameters:
8035 + dm      - The `DM`
8036 . time    - The time
8037 . localU  - The input field vector
8038 . funcs   - The functions to evaluate, one per field
8039 - mode    - The insertion mode for values
8040 
8041   Output Parameter:
8042 . localX  - The output vector
8043 
8044    Calling sequence of func:
8045 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8046 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8047 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8048 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8049 
8050 +  dim          - The spatial dimension
8051 .  Nf           - The number of input fields
8052 .  NfAux        - The number of input auxiliary fields
8053 .  uOff         - The offset of each field in u[]
8054 .  uOff_x       - The offset of each field in u_x[]
8055 .  u            - The field values at this point in space
8056 .  u_t          - The field time derivative at this point in space (or NULL)
8057 .  u_x          - The field derivatives at this point in space
8058 .  aOff         - The offset of each auxiliary field in u[]
8059 .  aOff_x       - The offset of each auxiliary field in u_x[]
8060 .  a            - The auxiliary field values at this point in space
8061 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8062 .  a_x          - The auxiliary field derivatives at this point in space
8063 .  t            - The current time
8064 .  x            - The coordinates of this point
8065 .  numConstants - The number of constants
8066 .  constants    - The value of each constant
8067 -  f            - The value of the function at this point in space
8068 
8069   Note:
8070   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.
8071   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
8072   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8073   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8074 
8075   Level: intermediate
8076 
8077   Developer Notes:
8078   This API is specific to only particular usage of `DM`
8079 
8080   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8081 
8082 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8083 @*/
8084 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)
8085 {
8086   PetscFunctionBegin;
8087   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8088   PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8089   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8090   PetscCall((dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX));
8091   PetscFunctionReturn(0);
8092 }
8093 
8094 /*@C
8095   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.
8096 
8097   Not collective
8098 
8099   Input Parameters:
8100 + dm      - The `DM`
8101 . time    - The time
8102 . label   - The `DMLabel` marking the portion of the domain to output
8103 . numIds  - The number of label ids to use
8104 . ids     - The label ids to use for marking
8105 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8106 . comps   - The components to set in the output, or NULL for all components
8107 . localU  - The input field vector
8108 . funcs   - The functions to evaluate, one per field
8109 - mode    - The insertion mode for values
8110 
8111   Output Parameter:
8112 . localX  - The output vector
8113 
8114    Calling sequence of func:
8115 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8116 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8117 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8118 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8119 
8120 +  dim          - The spatial dimension
8121 .  Nf           - The number of input fields
8122 .  NfAux        - The number of input auxiliary fields
8123 .  uOff         - The offset of each field in u[]
8124 .  uOff_x       - The offset of each field in u_x[]
8125 .  u            - The field values at this point in space
8126 .  u_t          - The field time derivative at this point in space (or NULL)
8127 .  u_x          - The field derivatives at this point in space
8128 .  aOff         - The offset of each auxiliary field in u[]
8129 .  aOff_x       - The offset of each auxiliary field in u_x[]
8130 .  a            - The auxiliary field values at this point in space
8131 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8132 .  a_x          - The auxiliary field derivatives at this point in space
8133 .  t            - The current time
8134 .  x            - The coordinates of this point
8135 .  numConstants - The number of constants
8136 .  constants    - The value of each constant
8137 -  f            - The value of the function at this point in space
8138 
8139   Note:
8140   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.
8141   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
8142   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8143   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8144 
8145   Level: intermediate
8146 
8147   Developer Notes:
8148   This API is specific to only particular usage of `DM`
8149 
8150   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8151 
8152 .seealso: `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8153 @*/
8154 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)
8155 {
8156   PetscFunctionBegin;
8157   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8158   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8159   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8160   PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8161   PetscFunctionReturn(0);
8162 }
8163 
8164 /*@C
8165   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.
8166 
8167   Not collective
8168 
8169   Input Parameters:
8170 + dm      - The `DM`
8171 . time    - The time
8172 . label   - The `DMLabel` marking the portion of the domain to output
8173 . numIds  - The number of label ids to use
8174 . ids     - The label ids to use for marking
8175 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8176 . comps   - The components to set in the output, or NULL for all components
8177 . U       - The input field vector
8178 . funcs   - The functions to evaluate, one per field
8179 - mode    - The insertion mode for values
8180 
8181   Output Parameter:
8182 . X       - The output vector
8183 
8184    Calling sequence of func:
8185 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8186 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8187 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8188 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8189 
8190 +  dim          - The spatial dimension
8191 .  Nf           - The number of input fields
8192 .  NfAux        - The number of input auxiliary fields
8193 .  uOff         - The offset of each field in u[]
8194 .  uOff_x       - The offset of each field in u_x[]
8195 .  u            - The field values at this point in space
8196 .  u_t          - The field time derivative at this point in space (or NULL)
8197 .  u_x          - The field derivatives at this point in space
8198 .  aOff         - The offset of each auxiliary field in u[]
8199 .  aOff_x       - The offset of each auxiliary field in u_x[]
8200 .  a            - The auxiliary field values at this point in space
8201 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8202 .  a_x          - The auxiliary field derivatives at this point in space
8203 .  t            - The current time
8204 .  x            - The coordinates of this point
8205 .  numConstants - The number of constants
8206 .  constants    - The value of each constant
8207 -  f            - The value of the function at this point in space
8208 
8209   Note:
8210   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.
8211   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
8212   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8213   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8214 
8215   Level: intermediate
8216 
8217   Developer Notes:
8218   This API is specific to only particular usage of `DM`
8219 
8220   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8221 
8222 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8223 @*/
8224 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)
8225 {
8226   DM  dmIn;
8227   Vec localU, localX;
8228 
8229   PetscFunctionBegin;
8230   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8231   PetscCall(VecGetDM(U, &dmIn));
8232   PetscCall(DMGetLocalVector(dmIn, &localU));
8233   PetscCall(DMGetLocalVector(dm, &localX));
8234   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8235   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8236   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8237   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8238   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8239   PetscCall(DMRestoreLocalVector(dm, &localX));
8240   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8241   PetscFunctionReturn(0);
8242 }
8243 
8244 /*@C
8245   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.
8246 
8247   Not collective
8248 
8249   Input Parameters:
8250 + dm      - The `DM`
8251 . time    - The time
8252 . label   - The `DMLabel` marking the portion of the domain boundary to output
8253 . numIds  - The number of label ids to use
8254 . ids     - The label ids to use for marking
8255 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8256 . comps   - The components to set in the output, or NULL for all components
8257 . localU  - The input field vector
8258 . funcs   - The functions to evaluate, one per field
8259 - mode    - The insertion mode for values
8260 
8261   Output Parameter:
8262 . localX  - The output vector
8263 
8264    Calling sequence of func:
8265 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8266 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8267 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8268 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8269 
8270 +  dim          - The spatial dimension
8271 .  Nf           - The number of input fields
8272 .  NfAux        - The number of input auxiliary fields
8273 .  uOff         - The offset of each field in u[]
8274 .  uOff_x       - The offset of each field in u_x[]
8275 .  u            - The field values at this point in space
8276 .  u_t          - The field time derivative at this point in space (or NULL)
8277 .  u_x          - The field derivatives at this point in space
8278 .  aOff         - The offset of each auxiliary field in u[]
8279 .  aOff_x       - The offset of each auxiliary field in u_x[]
8280 .  a            - The auxiliary field values at this point in space
8281 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8282 .  a_x          - The auxiliary field derivatives at this point in space
8283 .  t            - The current time
8284 .  x            - The coordinates of this point
8285 .  n            - The face normal
8286 .  numConstants - The number of constants
8287 .  constants    - The value of each constant
8288 -  f            - The value of the function at this point in space
8289 
8290   Note:
8291   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.
8292   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
8293   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8294   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8295 
8296   Level: intermediate
8297 
8298   Developer Notes:
8299   This API is specific to only particular usage of `DM`
8300 
8301   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8302 
8303 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8304 @*/
8305 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)
8306 {
8307   PetscFunctionBegin;
8308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8309   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8310   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8311   PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8312   PetscFunctionReturn(0);
8313 }
8314 
8315 /*@C
8316   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8317 
8318   Collective on dm
8319 
8320   Input Parameters:
8321 + dm    - The `DM`
8322 . time  - The time
8323 . funcs - The functions to evaluate for each field component
8324 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8325 - X     - The coefficient vector u_h, a global vector
8326 
8327   Output Parameter:
8328 . diff - The diff ||u - u_h||_2
8329 
8330   Level: developer
8331 
8332   Developer Notes:
8333   This API is specific to only particular usage of `DM`
8334 
8335   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8336 
8337 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8338 @*/
8339 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8340 {
8341   PetscFunctionBegin;
8342   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8343   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8344   PetscCall((dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff));
8345   PetscFunctionReturn(0);
8346 }
8347 
8348 /*@C
8349   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8350 
8351   Collective on dm
8352 
8353   Input Parameters:
8354 + dm    - The `DM`
8355 , time  - The time
8356 . funcs - The gradient functions to evaluate for each field component
8357 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8358 . X     - The coefficient vector u_h, a global vector
8359 - n     - The vector to project along
8360 
8361   Output Parameter:
8362 . diff - The diff ||(grad u - grad u_h) . n||_2
8363 
8364   Level: developer
8365 
8366   Developer Notes:
8367   This API is specific to only particular usage of `DM`
8368 
8369   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8370 
8371 .seealso: `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8372 @*/
8373 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)
8374 {
8375   PetscFunctionBegin;
8376   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8377   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8378   PetscCall((dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff));
8379   PetscFunctionReturn(0);
8380 }
8381 
8382 /*@C
8383   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8384 
8385   Collective on dm
8386 
8387   Input Parameters:
8388 + dm    - The `DM`
8389 . time  - The time
8390 . funcs - The functions to evaluate for each field component
8391 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8392 - X     - The coefficient vector u_h, a global vector
8393 
8394   Output Parameter:
8395 . diff - The array of differences, ||u^f - u^f_h||_2
8396 
8397   Level: developer
8398 
8399   Developer Notes:
8400   This API is specific to only particular usage of `DM`
8401 
8402   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8403 
8404 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8405 @*/
8406 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8407 {
8408   PetscFunctionBegin;
8409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8410   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8411   PetscCall((dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff));
8412   PetscFunctionReturn(0);
8413 }
8414 
8415 /*@C
8416  DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8417 
8418  Not Collective
8419 
8420  Input Parameter:
8421 .  dm    - The `DM`
8422 
8423  Output Parameters:
8424 +  nranks - the number of neighbours
8425 -  ranks - the neighbors ranks
8426 
8427  Note:
8428  Do not free the array, it is freed when the `DM` is destroyed.
8429 
8430  Level: beginner
8431 
8432  .seealso: `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8433 @*/
8434 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8435 {
8436   PetscFunctionBegin;
8437   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8438   PetscCall((dm->ops->getneighbors)(dm, nranks, ranks));
8439   PetscFunctionReturn(0);
8440 }
8441 
8442 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8443 
8444 /*
8445     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8446     This has be a different function because it requires DM which is not defined in the Mat library
8447 */
8448 PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8449 {
8450   PetscFunctionBegin;
8451   if (coloring->ctype == IS_COLORING_LOCAL) {
8452     Vec x1local;
8453     DM  dm;
8454     PetscCall(MatGetDM(J, &dm));
8455     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8456     PetscCall(DMGetLocalVector(dm, &x1local));
8457     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8458     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8459     x1 = x1local;
8460   }
8461   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8462   if (coloring->ctype == IS_COLORING_LOCAL) {
8463     DM dm;
8464     PetscCall(MatGetDM(J, &dm));
8465     PetscCall(DMRestoreLocalVector(dm, &x1));
8466   }
8467   PetscFunctionReturn(0);
8468 }
8469 
8470 /*@
8471     MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8472 
8473     Input Parameter:
8474 .    coloring - the `MatFDColoring` object
8475 
8476     Developer Note:
8477     this routine exists because the PETSc `Mat` library does not know about the `DM` objects
8478 
8479     Level: advanced
8480 
8481 .seealso: `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8482 @*/
8483 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8484 {
8485   PetscFunctionBegin;
8486   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8487   PetscFunctionReturn(0);
8488 }
8489 
8490 /*@
8491     DMGetCompatibility - determine if two `DM`s are compatible
8492 
8493     Collective
8494 
8495     Input Parameters:
8496 +    dm1 - the first `DM`
8497 -    dm2 - the second `DM`
8498 
8499     Output Parameters:
8500 +    compatible - whether or not the two `DM`s are compatible
8501 -    set - whether or not the compatible value was actually determined and set
8502 
8503     Notes:
8504     Two `DM`s are deemed compatible if they represent the same parallel decomposition
8505     of the same topology. This implies that the section (field data) on one
8506     "makes sense" with respect to the topology and parallel decomposition of the other.
8507     Loosely speaking, compatible `DM`s represent the same domain and parallel
8508     decomposition, but hold different data.
8509 
8510     Typically, one would confirm compatibility if intending to simultaneously iterate
8511     over a pair of vectors obtained from different `DM`s.
8512 
8513     For example, two `DMDA` objects are compatible if they have the same local
8514     and global sizes and the same stencil width. They can have different numbers
8515     of degrees of freedom per node. Thus, one could use the node numbering from
8516     either `DM` in bounds for a loop over vectors derived from either `DM`.
8517 
8518     Consider the operation of summing data living on a 2-dof `DMDA` to data living
8519     on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8520 .vb
8521   ...
8522   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8523   if (set && compatible)  {
8524     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8525     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8526     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8527     for (j=y; j<y+n; ++j) {
8528       for (i=x; i<x+m, ++i) {
8529         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8530       }
8531     }
8532     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8533     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8534   } else {
8535     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8536   }
8537   ...
8538 .ve
8539 
8540     Checking compatibility might be expensive for a given implementation of `DM`,
8541     or might be impossible to unambiguously confirm or deny. For this reason,
8542     this function may decline to determine compatibility, and hence users should
8543     always check the "set" output parameter.
8544 
8545     A `DM` is always compatible with itself.
8546 
8547     In the current implementation, `DM`s which live on "unequal" communicators
8548     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8549     incompatible.
8550 
8551     This function is labeled "Collective," as information about all subdomains
8552     is required on each rank. However, in `DM` implementations which store all this
8553     information locally, this function may be merely "Logically Collective".
8554 
8555     Developer Note:
8556     Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8557     iff B is compatible with A. Thus, this function checks the implementations
8558     of both dm and dmc (if they are of different types), attempting to determine
8559     compatibility. It is left to `DM` implementers to ensure that symmetry is
8560     preserved. The simplest way to do this is, when implementing type-specific
8561     logic for this function, is to check for existing logic in the implementation
8562     of other `DM` types and let *set = PETSC_FALSE if found.
8563 
8564     Level: advanced
8565 
8566 .seealso: `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8567 @*/
8568 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8569 {
8570   PetscMPIInt compareResult;
8571   DMType      type, type2;
8572   PetscBool   sameType;
8573 
8574   PetscFunctionBegin;
8575   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8576   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8577 
8578   /* Declare a DM compatible with itself */
8579   if (dm1 == dm2) {
8580     *set        = PETSC_TRUE;
8581     *compatible = PETSC_TRUE;
8582     PetscFunctionReturn(0);
8583   }
8584 
8585   /* Declare a DM incompatible with a DM that lives on an "unequal"
8586      communicator. Note that this does not preclude compatibility with
8587      DMs living on "congruent" or "similar" communicators, but this must be
8588      determined by the implementation-specific logic */
8589   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8590   if (compareResult == MPI_UNEQUAL) {
8591     *set        = PETSC_TRUE;
8592     *compatible = PETSC_FALSE;
8593     PetscFunctionReturn(0);
8594   }
8595 
8596   /* Pass to the implementation-specific routine, if one exists. */
8597   if (dm1->ops->getcompatibility) {
8598     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8599     if (*set) PetscFunctionReturn(0);
8600   }
8601 
8602   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8603      with an implementation of this function from dm2 */
8604   PetscCall(DMGetType(dm1, &type));
8605   PetscCall(DMGetType(dm2, &type2));
8606   PetscCall(PetscStrcmp(type, type2, &sameType));
8607   if (!sameType && dm2->ops->getcompatibility) {
8608     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8609   } else {
8610     *set = PETSC_FALSE;
8611   }
8612   PetscFunctionReturn(0);
8613 }
8614 
8615 /*@C
8616   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8617 
8618   Logically Collective on dm
8619 
8620   Input Parameters:
8621 + DM - the `DM`
8622 . f - the monitor function
8623 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
8624 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
8625 
8626   Options Database Keys:
8627 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8628                             does not cancel those set via the options database.
8629 
8630   Note:
8631   Several different monitoring routines may be set by calling
8632   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8633   order in which they were set.
8634 
8635   Fortran Note:
8636   Only a single monitor function can be set for each `DM` object
8637 
8638   Developer Note:
8639   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8640 
8641   Level: intermediate
8642 
8643 .seealso: `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8644 @*/
8645 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8646 {
8647   PetscInt m;
8648 
8649   PetscFunctionBegin;
8650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8651   for (m = 0; m < dm->numbermonitors; ++m) {
8652     PetscBool identical;
8653 
8654     PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8655     if (identical) PetscFunctionReturn(0);
8656   }
8657   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8658   dm->monitor[dm->numbermonitors]          = f;
8659   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8660   dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8661   PetscFunctionReturn(0);
8662 }
8663 
8664 /*@
8665   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8666 
8667   Logically Collective on dm
8668 
8669   Input Parameter:
8670 . dm - the DM
8671 
8672   Options Database Key:
8673 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8674   into a code by calls to `DMonitorSet()`, but does not cancel those
8675   set via the options database
8676 
8677   Note:
8678   There is no way to clear one specific monitor from a `DM` object.
8679 
8680   Level: intermediate
8681 
8682 .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8683 @*/
8684 PetscErrorCode DMMonitorCancel(DM dm)
8685 {
8686   PetscInt m;
8687 
8688   PetscFunctionBegin;
8689   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8690   for (m = 0; m < dm->numbermonitors; ++m) {
8691     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8692   }
8693   dm->numbermonitors = 0;
8694   PetscFunctionReturn(0);
8695 }
8696 
8697 /*@C
8698   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8699 
8700   Collective on dm
8701 
8702   Input Parameters:
8703 + dm   - `DM` object you wish to monitor
8704 . name - the monitor type one is seeking
8705 . help - message indicating what monitoring is done
8706 . manual - manual page for the monitor
8707 . monitor - the monitor function
8708 - 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
8709 
8710   Output Parameter:
8711 . flg - Flag set if the monitor was created
8712 
8713   Level: developer
8714 
8715 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8716           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8717           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
8718           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8719           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8720           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8721           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8722 @*/
8723 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8724 {
8725   PetscViewer       viewer;
8726   PetscViewerFormat format;
8727 
8728   PetscFunctionBegin;
8729   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8730   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
8731   if (*flg) {
8732     PetscViewerAndFormat *vf;
8733 
8734     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
8735     PetscCall(PetscObjectDereference((PetscObject)viewer));
8736     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
8737     PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
8738   }
8739   PetscFunctionReturn(0);
8740 }
8741 
8742 /*@
8743    DMMonitor - runs the user provided monitor routines, if they exist
8744 
8745    Collective on dm
8746 
8747    Input Parameters:
8748 .  dm - The `DM`
8749 
8750    Level: developer
8751 
8752    Question:
8753    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
8754    since some `DM` have no concept of discretization
8755 
8756 .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`
8757 @*/
8758 PetscErrorCode DMMonitor(DM dm)
8759 {
8760   PetscInt m;
8761 
8762   PetscFunctionBegin;
8763   if (!dm) PetscFunctionReturn(0);
8764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8765   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
8766   PetscFunctionReturn(0);
8767 }
8768 
8769 /*@
8770   DMComputeError - Computes the error assuming the user has provided the exact solution functions
8771 
8772   Collective on dm
8773 
8774   Input Parameters:
8775 + dm     - The `DM`
8776 - sol    - The solution vector
8777 
8778   Input/Output Parameter:
8779 . errors - An array of length Nf, the number of fields, or NULL for no output; on output
8780            contains the error in each field
8781 
8782   Output Parameter:
8783 . errorVec - A vector to hold the cellwise error (may be NULL)
8784 
8785   Note:
8786   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
8787 
8788   Level: developer
8789 
8790 .seealso: `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
8791 @*/
8792 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
8793 {
8794   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
8795   void    **ctxs;
8796   PetscReal time;
8797   PetscInt  Nf, f, Nds, s;
8798 
8799   PetscFunctionBegin;
8800   PetscCall(DMGetNumFields(dm, &Nf));
8801   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
8802   PetscCall(DMGetNumDS(dm, &Nds));
8803   for (s = 0; s < Nds; ++s) {
8804     PetscDS         ds;
8805     DMLabel         label;
8806     IS              fieldIS;
8807     const PetscInt *fields;
8808     PetscInt        dsNf;
8809 
8810     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
8811     PetscCall(PetscDSGetNumFields(ds, &dsNf));
8812     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
8813     for (f = 0; f < dsNf; ++f) {
8814       const PetscInt field = fields[f];
8815       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
8816     }
8817     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
8818   }
8819   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);
8820   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
8821   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
8822   if (errorVec) {
8823     DM             edm;
8824     DMPolytopeType ct;
8825     PetscBool      simplex;
8826     PetscInt       dim, cStart, Nf;
8827 
8828     PetscCall(DMClone(dm, &edm));
8829     PetscCall(DMGetDimension(edm, &dim));
8830     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
8831     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8832     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
8833     PetscCall(DMGetNumFields(dm, &Nf));
8834     for (f = 0; f < Nf; ++f) {
8835       PetscFE         fe, efe;
8836       PetscQuadrature q;
8837       const char     *name;
8838 
8839       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
8840       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
8841       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
8842       PetscCall(PetscObjectSetName((PetscObject)efe, name));
8843       PetscCall(PetscFEGetQuadrature(fe, &q));
8844       PetscCall(PetscFESetQuadrature(efe, q));
8845       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
8846       PetscCall(PetscFEDestroy(&efe));
8847     }
8848     PetscCall(DMCreateDS(edm));
8849 
8850     PetscCall(DMCreateGlobalVector(edm, errorVec));
8851     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
8852     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
8853     PetscCall(DMDestroy(&edm));
8854   }
8855   PetscCall(PetscFree2(exactSol, ctxs));
8856   PetscFunctionReturn(0);
8857 }
8858 
8859 /*@
8860   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
8861 
8862   Not collective
8863 
8864   Input Parameter:
8865 . dm     - The `DM`
8866 
8867   Output Parameter:
8868 . numAux - The number of auxiliary data vectors
8869 
8870   Level: advanced
8871 
8872 .seealso: `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8873 @*/
8874 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
8875 {
8876   PetscFunctionBegin;
8877   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8878   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
8879   PetscFunctionReturn(0);
8880 }
8881 
8882 /*@
8883   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
8884 
8885   Not collective
8886 
8887   Input Parameters:
8888 + dm     - The `DM`
8889 . label  - The `DMLabel`
8890 . value  - The label value indicating the region
8891 - part   - The equation part, or 0 if unused
8892 
8893   Output Parameter:
8894 . aux    - The `Vec` holding auxiliary field data
8895 
8896   Note:
8897   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
8898 
8899   Level: advanced
8900 
8901 .seealso: `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
8902 @*/
8903 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
8904 {
8905   PetscHashAuxKey key, wild = {NULL, 0, 0};
8906   PetscBool       has;
8907 
8908   PetscFunctionBegin;
8909   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8910   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
8911   key.label = label;
8912   key.value = value;
8913   key.part  = part;
8914   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
8915   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
8916   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
8917   PetscFunctionReturn(0);
8918 }
8919 
8920 /*@
8921   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
8922 
8923   Not collective because auxilary vectors are not parallel
8924 
8925   Input Parameters:
8926 + dm     - The `DM`
8927 . label  - The `DMLabel`
8928 . value  - The label value indicating the region
8929 . part   - The equation part, or 0 if unused
8930 - aux    - The `Vec` holding auxiliary field data
8931 
8932   Level: advanced
8933 
8934 .seealso: `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
8935 @*/
8936 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
8937 {
8938   Vec             old;
8939   PetscHashAuxKey key;
8940 
8941   PetscFunctionBegin;
8942   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8943   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
8944   key.label = label;
8945   key.value = value;
8946   key.part  = part;
8947   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
8948   PetscCall(PetscObjectReference((PetscObject)aux));
8949   PetscCall(PetscObjectDereference((PetscObject)old));
8950   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
8951   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
8952   PetscFunctionReturn(0);
8953 }
8954 
8955 /*@C
8956   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
8957 
8958   Not collective
8959 
8960   Input Parameter:
8961 . dm      - The `DM`
8962 
8963   Output Parameters:
8964 + labels  - The `DMLabel`s for each `Vec`
8965 . values  - The label values for each `Vec`
8966 - parts   - The equation parts for each `Vec`
8967 
8968   Note:
8969   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
8970 
8971   Level: advanced
8972 
8973 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMSetAuxiliaryVec()`, DMCopyAuxiliaryVec()`
8974 @*/
8975 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
8976 {
8977   PetscHashAuxKey *keys;
8978   PetscInt         n, i, off = 0;
8979 
8980   PetscFunctionBegin;
8981   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8982   PetscValidPointer(labels, 2);
8983   PetscValidIntPointer(values, 3);
8984   PetscValidIntPointer(parts, 4);
8985   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
8986   PetscCall(PetscMalloc1(n, &keys));
8987   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
8988   for (i = 0; i < n; ++i) {
8989     labels[i] = keys[i].label;
8990     values[i] = keys[i].value;
8991     parts[i]  = keys[i].part;
8992   }
8993   PetscCall(PetscFree(keys));
8994   PetscFunctionReturn(0);
8995 }
8996 
8997 /*@
8998   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
8999 
9000   Not collective
9001 
9002   Input Parameter:
9003 . dm    - The `DM`
9004 
9005   Output Parameter:
9006 . dmNew - The new `DM`, now with the same auxiliary data
9007 
9008   Level: advanced
9009 
9010   Note:
9011   This is a shallow copy of the auxiliary vectors
9012 
9013 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9014 @*/
9015 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9016 {
9017   PetscFunctionBegin;
9018   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9019   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9020   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9021   PetscFunctionReturn(0);
9022 }
9023 
9024 /*@C
9025   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9026 
9027   Not collective
9028 
9029   Input Parameters:
9030 + ct         - The `DMPolytopeType`
9031 . sourceCone - The source arrangement of faces
9032 - targetCone - The target arrangement of faces
9033 
9034   Output Parameters:
9035 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9036 - found - Flag indicating that a suitable orientation was found
9037 
9038   Level: advanced
9039 
9040   Note:
9041   An arrangement is a face order combined with an orientation for each face
9042 
9043   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
9044   that labels each arrangement (face ordering plus orientation for each face).
9045 
9046   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9047 
9048 .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9049 @*/
9050 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9051 {
9052   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9053   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
9054   PetscInt       o, c;
9055 
9056   PetscFunctionBegin;
9057   if (!nO) {
9058     *ornt  = 0;
9059     *found = PETSC_TRUE;
9060     PetscFunctionReturn(0);
9061   }
9062   for (o = -nO; o < nO; ++o) {
9063     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
9064 
9065     for (c = 0; c < cS; ++c)
9066       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9067     if (c == cS) {
9068       *ornt = o;
9069       break;
9070     }
9071   }
9072   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9073   PetscFunctionReturn(0);
9074 }
9075 
9076 /*@C
9077   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9078 
9079   Not collective
9080 
9081   Input Parameters:
9082 + ct         - The `DMPolytopeType`
9083 . sourceCone - The source arrangement of faces
9084 - targetCone - The target arrangement of faces
9085 
9086   Output Parameters:
9087 . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9088 
9089   Level: advanced
9090 
9091   Note:
9092   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9093 
9094   Developer Note:
9095   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9096 
9097 .seealso: `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9098 @*/
9099 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9100 {
9101   PetscBool found;
9102 
9103   PetscFunctionBegin;
9104   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9105   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9106   PetscFunctionReturn(0);
9107 }
9108 
9109 /*@C
9110   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9111 
9112   Not collective
9113 
9114   Input Parameters:
9115 + ct         - The `DMPolytopeType`
9116 . sourceVert - The source arrangement of vertices
9117 - targetVert - The target arrangement of vertices
9118 
9119   Output Parameters:
9120 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9121 - found - Flag indicating that a suitable orientation was found
9122 
9123   Level: advanced
9124 
9125   Note:
9126   An arrangement is a vertex order
9127 
9128   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
9129   that labels each arrangement (vertex ordering).
9130 
9131   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9132 
9133 .seealso: `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()`
9134 @*/
9135 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9136 {
9137   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9138   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
9139   PetscInt       o, c;
9140 
9141   PetscFunctionBegin;
9142   if (!nO) {
9143     *ornt  = 0;
9144     *found = PETSC_TRUE;
9145     PetscFunctionReturn(0);
9146   }
9147   for (o = -nO; o < nO; ++o) {
9148     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
9149 
9150     for (c = 0; c < cS; ++c)
9151       if (sourceVert[arr[c]] != targetVert[c]) break;
9152     if (c == cS) {
9153       *ornt = o;
9154       break;
9155     }
9156   }
9157   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9158   PetscFunctionReturn(0);
9159 }
9160 
9161 /*@C
9162   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9163 
9164   Not collective
9165 
9166   Input Parameters:
9167 + ct         - The `DMPolytopeType`
9168 . sourceCone - The source arrangement of vertices
9169 - targetCone - The target arrangement of vertices
9170 
9171   Output Parameters:
9172 . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9173 
9174   Level: advanced
9175 
9176   Note:
9177   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9178 
9179   Developer Note:
9180   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9181 
9182 .seealso: `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9183 @*/
9184 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9185 {
9186   PetscBool found;
9187 
9188   PetscFunctionBegin;
9189   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9190   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9191   PetscFunctionReturn(0);
9192 }
9193 
9194 /*@C
9195   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9196 
9197   Not collective
9198 
9199   Input Parameters:
9200 + ct    - The `DMPolytopeType`
9201 - point - Coordinates of the point
9202 
9203   Output Parameters:
9204 . inside  - Flag indicating whether the point is inside the reference cell of given type
9205 
9206   Level: advanced
9207 
9208 .seealso: `DM`, `DMPolytopeType`, `DMLocatePoints()`
9209 @*/
9210 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9211 {
9212   PetscReal sum = 0.0;
9213   PetscInt  d;
9214 
9215   PetscFunctionBegin;
9216   *inside = PETSC_TRUE;
9217   switch (ct) {
9218   case DM_POLYTOPE_TRIANGLE:
9219   case DM_POLYTOPE_TETRAHEDRON:
9220     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9221       if (point[d] < -1.0) {
9222         *inside = PETSC_FALSE;
9223         break;
9224       }
9225       sum += point[d];
9226     }
9227     if (sum > PETSC_SMALL) {
9228       *inside = PETSC_FALSE;
9229       break;
9230     }
9231     break;
9232   case DM_POLYTOPE_QUADRILATERAL:
9233   case DM_POLYTOPE_HEXAHEDRON:
9234     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9235       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9236         *inside = PETSC_FALSE;
9237         break;
9238       }
9239     break;
9240   default:
9241     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9242   }
9243   PetscFunctionReturn(0);
9244 }
9245