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