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