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