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