xref: /petsc/src/dm/interface/dm.c (revision 7a5338279d92d13360d231b9bd26d284f35eaa49)
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   Fortran Note:
557   Pass in a string 'prefix' of
558   sufficient length to hold the prefix.
559 
560 .seealso: [](ch_dmbase), `DM`, `DMSetOptionsPrefix()`, `DMAppendOptionsPrefix()`, `DMSetFromOptions()`
561 @*/
562 PetscErrorCode DMGetOptionsPrefix(DM dm, const char *prefix[])
563 {
564   PetscFunctionBegin;
565   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
566   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, prefix));
567   PetscFunctionReturn(PETSC_SUCCESS);
568 }
569 
570 static PetscErrorCode DMCountNonCyclicReferences_Internal(DM dm, PetscBool recurseCoarse, PetscBool recurseFine, PetscInt *ncrefct)
571 {
572   PetscInt refct = ((PetscObject)dm)->refct;
573 
574   PetscFunctionBegin;
575   *ncrefct = 0;
576   if (dm->coarseMesh && dm->coarseMesh->fineMesh == dm) {
577     refct--;
578     if (recurseCoarse) {
579       PetscInt coarseCount;
580 
581       PetscCall(DMCountNonCyclicReferences_Internal(dm->coarseMesh, PETSC_TRUE, PETSC_FALSE, &coarseCount));
582       refct += coarseCount;
583     }
584   }
585   if (dm->fineMesh && dm->fineMesh->coarseMesh == dm) {
586     refct--;
587     if (recurseFine) {
588       PetscInt fineCount;
589 
590       PetscCall(DMCountNonCyclicReferences_Internal(dm->fineMesh, PETSC_FALSE, PETSC_TRUE, &fineCount));
591       refct += fineCount;
592     }
593   }
594   *ncrefct = refct;
595   PetscFunctionReturn(PETSC_SUCCESS);
596 }
597 
598 /* Generic wrapper for DMCountNonCyclicReferences_Internal() */
599 PetscErrorCode DMCountNonCyclicReferences(PetscObject dm, PetscInt *ncrefct)
600 {
601   PetscFunctionBegin;
602   PetscCall(DMCountNonCyclicReferences_Internal((DM)dm, PETSC_TRUE, PETSC_TRUE, ncrefct));
603   PetscFunctionReturn(PETSC_SUCCESS);
604 }
605 
606 PetscErrorCode DMDestroyLabelLinkList_Internal(DM dm)
607 {
608   DMLabelLink next = dm->labels;
609 
610   PetscFunctionBegin;
611   /* destroy the labels */
612   while (next) {
613     DMLabelLink tmp = next->next;
614 
615     if (next->label == dm->depthLabel) dm->depthLabel = NULL;
616     if (next->label == dm->celltypeLabel) dm->celltypeLabel = NULL;
617     PetscCall(DMLabelDestroy(&next->label));
618     PetscCall(PetscFree(next));
619     next = tmp;
620   }
621   dm->labels = NULL;
622   PetscFunctionReturn(PETSC_SUCCESS);
623 }
624 
625 static PetscErrorCode DMDestroyCoordinates_Private(DMCoordinates *c)
626 {
627   PetscFunctionBegin;
628   c->dim = PETSC_DEFAULT;
629   PetscCall(DMDestroy(&c->dm));
630   PetscCall(VecDestroy(&c->x));
631   PetscCall(VecDestroy(&c->xl));
632   PetscCall(DMFieldDestroy(&c->field));
633   PetscFunctionReturn(PETSC_SUCCESS);
634 }
635 
636 /*@
637   DMDestroy - Destroys a `DM`.
638 
639   Collective
640 
641   Input Parameter:
642 . dm - the `DM` object to destroy
643 
644   Level: developer
645 
646 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMType`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
647 @*/
648 PetscErrorCode DMDestroy(DM *dm)
649 {
650   PetscInt cnt;
651 
652   PetscFunctionBegin;
653   if (!*dm) PetscFunctionReturn(PETSC_SUCCESS);
654   PetscValidHeaderSpecific(*dm, DM_CLASSID, 1);
655 
656   /* count all non-cyclic references in the doubly-linked list of coarse<->fine meshes */
657   PetscCall(DMCountNonCyclicReferences_Internal(*dm, PETSC_TRUE, PETSC_TRUE, &cnt));
658   --((PetscObject)*dm)->refct;
659   if (--cnt > 0) {
660     *dm = NULL;
661     PetscFunctionReturn(PETSC_SUCCESS);
662   }
663   if (((PetscObject)*dm)->refct < 0) PetscFunctionReturn(PETSC_SUCCESS);
664   ((PetscObject)*dm)->refct = 0;
665 
666   PetscCall(DMClearGlobalVectors(*dm));
667   PetscCall(DMClearLocalVectors(*dm));
668   PetscCall(DMClearNamedGlobalVectors(*dm));
669   PetscCall(DMClearNamedLocalVectors(*dm));
670 
671   /* Destroy the list of hooks */
672   {
673     DMCoarsenHookLink link, next;
674     for (link = (*dm)->coarsenhook; link; link = next) {
675       next = link->next;
676       PetscCall(PetscFree(link));
677     }
678     (*dm)->coarsenhook = NULL;
679   }
680   {
681     DMRefineHookLink link, next;
682     for (link = (*dm)->refinehook; link; link = next) {
683       next = link->next;
684       PetscCall(PetscFree(link));
685     }
686     (*dm)->refinehook = NULL;
687   }
688   {
689     DMSubDomainHookLink link, next;
690     for (link = (*dm)->subdomainhook; link; link = next) {
691       next = link->next;
692       PetscCall(PetscFree(link));
693     }
694     (*dm)->subdomainhook = NULL;
695   }
696   {
697     DMGlobalToLocalHookLink link, next;
698     for (link = (*dm)->gtolhook; link; link = next) {
699       next = link->next;
700       PetscCall(PetscFree(link));
701     }
702     (*dm)->gtolhook = NULL;
703   }
704   {
705     DMLocalToGlobalHookLink link, next;
706     for (link = (*dm)->ltoghook; link; link = next) {
707       next = link->next;
708       PetscCall(PetscFree(link));
709     }
710     (*dm)->ltoghook = NULL;
711   }
712   /* Destroy the work arrays */
713   {
714     DMWorkLink link, next;
715     PetscCheck(!(*dm)->workout, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Work array still checked out %p %p", (void *)(*dm)->workout, (*dm)->workout->mem);
716     for (link = (*dm)->workin; link; link = next) {
717       next = link->next;
718       PetscCall(PetscFree(link->mem));
719       PetscCall(PetscFree(link));
720     }
721     (*dm)->workin = NULL;
722   }
723   /* destroy the labels */
724   PetscCall(DMDestroyLabelLinkList_Internal(*dm));
725   /* destroy the fields */
726   PetscCall(DMClearFields(*dm));
727   /* destroy the boundaries */
728   {
729     DMBoundary next = (*dm)->boundary;
730     while (next) {
731       DMBoundary b = next;
732 
733       next = b->next;
734       PetscCall(PetscFree(b));
735     }
736   }
737 
738   PetscCall(PetscObjectDestroy(&(*dm)->dmksp));
739   PetscCall(PetscObjectDestroy(&(*dm)->dmsnes));
740   PetscCall(PetscObjectDestroy(&(*dm)->dmts));
741 
742   if ((*dm)->ctx && (*dm)->ctxdestroy) PetscCall((*(*dm)->ctxdestroy)(&(*dm)->ctx));
743   PetscCall(MatFDColoringDestroy(&(*dm)->fd));
744   PetscCall(ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap));
745   PetscCall(PetscFree((*dm)->vectype));
746   PetscCall(PetscFree((*dm)->mattype));
747 
748   PetscCall(PetscSectionDestroy(&(*dm)->localSection));
749   PetscCall(PetscSectionDestroy(&(*dm)->globalSection));
750   PetscCall(PetscFree((*dm)->reorderSectionType));
751   PetscCall(PetscLayoutDestroy(&(*dm)->map));
752   PetscCall(PetscSectionDestroy(&(*dm)->defaultConstraint.section));
753   PetscCall(MatDestroy(&(*dm)->defaultConstraint.mat));
754   PetscCall(PetscSFDestroy(&(*dm)->sf));
755   PetscCall(PetscSFDestroy(&(*dm)->sectionSF));
756   if ((*dm)->sfNatural) PetscCall(PetscSFDestroy(&(*dm)->sfNatural));
757   PetscCall(PetscObjectDereference((PetscObject)(*dm)->sfMigration));
758   PetscCall(DMClearAuxiliaryVec(*dm));
759   PetscCall(PetscHMapAuxDestroy(&(*dm)->auxData));
760   if ((*dm)->coarseMesh && (*dm)->coarseMesh->fineMesh == *dm) PetscCall(DMSetFineDM((*dm)->coarseMesh, NULL));
761 
762   PetscCall(DMDestroy(&(*dm)->coarseMesh));
763   if ((*dm)->fineMesh && (*dm)->fineMesh->coarseMesh == *dm) PetscCall(DMSetCoarseDM((*dm)->fineMesh, NULL));
764   PetscCall(DMDestroy(&(*dm)->fineMesh));
765   PetscCall(PetscFree((*dm)->Lstart));
766   PetscCall(PetscFree((*dm)->L));
767   PetscCall(PetscFree((*dm)->maxCell));
768   PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[0]));
769   PetscCall(DMDestroyCoordinates_Private(&(*dm)->coordinates[1]));
770   if ((*dm)->transformDestroy) PetscCall((*(*dm)->transformDestroy)(*dm, (*dm)->transformCtx));
771   PetscCall(DMDestroy(&(*dm)->transformDM));
772   PetscCall(VecDestroy(&(*dm)->transform));
773   for (PetscInt i = 0; i < (*dm)->periodic.num_affines; i++) {
774     PetscCall(VecScatterDestroy(&(*dm)->periodic.affine_to_local[i]));
775     PetscCall(VecDestroy(&(*dm)->periodic.affine[i]));
776   }
777   if ((*dm)->periodic.num_affines > 0) PetscCall(PetscFree2((*dm)->periodic.affine_to_local, (*dm)->periodic.affine));
778 
779   PetscCall(DMClearDS(*dm));
780   PetscCall(DMDestroy(&(*dm)->dmBC));
781   /* if memory was published with SAWs then destroy it */
782   PetscCall(PetscObjectSAWsViewOff((PetscObject)*dm));
783 
784   PetscTryTypeMethod(*dm, destroy);
785   PetscCall(DMMonitorCancel(*dm));
786   PetscCall(DMCeedDestroy(&(*dm)->dmceed));
787 #ifdef PETSC_HAVE_LIBCEED
788   PetscCallCEED(CeedElemRestrictionDestroy(&(*dm)->ceedERestrict));
789   PetscCallCEED(CeedDestroy(&(*dm)->ceed));
790 #endif
791   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
792   PetscCall(PetscHeaderDestroy(dm));
793   PetscFunctionReturn(PETSC_SUCCESS);
794 }
795 
796 /*@
797   DMSetUp - sets up the data structures inside a `DM` object
798 
799   Collective
800 
801   Input Parameter:
802 . dm - the `DM` object to setup
803 
804   Level: intermediate
805 
806   Note:
807   This is usually called after various parameter setting operations and `DMSetFromOptions()` are called on the `DM`
808 
809 .seealso: [](ch_dmbase), `DM`, `DMCreate()`, `DMSetType()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
810 @*/
811 PetscErrorCode DMSetUp(DM dm)
812 {
813   PetscFunctionBegin;
814   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
815   if (dm->setupcalled) PetscFunctionReturn(PETSC_SUCCESS);
816   PetscTryTypeMethod(dm, setup);
817   dm->setupcalled = PETSC_TRUE;
818   PetscFunctionReturn(PETSC_SUCCESS);
819 }
820 
821 /*@
822   DMSetFromOptions - sets parameters in a `DM` from the options database
823 
824   Collective
825 
826   Input Parameter:
827 . dm - the `DM` object to set options for
828 
829   Options Database Keys:
830 + -dm_preallocate_only                               - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
831 . -dm_vec_type <type>                                - type of vector to create inside `DM`
832 . -dm_mat_type <type>                                - type of matrix to create inside `DM`
833 . -dm_is_coloring_type                               - <global or local>
834 . -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`
835 . -dm_plex_option_phases <ph0_, ph1_, ...>           - List of prefixes for option processing phases
836 . -dm_plex_filename <str>                            - File containing a mesh
837 . -dm_plex_boundary_filename <str>                   - File containing a mesh boundary
838 . -dm_plex_name <str>                                - Name of the mesh in the file
839 . -dm_plex_shape <shape>                             - The domain shape, such as `BOX`, `SPHERE`, etc.
840 . -dm_plex_cell <ct>                                 - Cell shape
841 . -dm_plex_reference_cell_domain <bool>              - Use a reference cell domain
842 . -dm_plex_dim <dim>                                 - Set the topological dimension
843 . -dm_plex_simplex <bool>                            - `PETSC_TRUE` for simplex elements, `PETSC_FALSE` for tensor elements
844 . -dm_plex_interpolate <bool>                        - `PETSC_TRUE` turns on topological interpolation (creating edges and faces)
845 . -dm_plex_orient <bool>                             - `PETSC_TRUE` turns on topological orientation (flipping edges and faces)
846 . -dm_plex_scale <sc>                                - Scale factor for mesh coordinates
847 . -dm_coord_remap <bool>                             - Map coordinates using a function
848 . -dm_coord_map <mapname>                            - Select a builtin coordinate map
849 . -dm_coord_map_params <p0,p1,p2,...>                - Set coordinate mapping parameters
850 . -dm_plex_box_faces <m,n,p>                         - Number of faces along each dimension
851 . -dm_plex_box_lower <x,y,z>                         - Specify lower-left-bottom coordinates for the box
852 . -dm_plex_box_upper <x,y,z>                         - Specify upper-right-top coordinates for the box
853 . -dm_plex_box_bd <bx,by,bz>                         - Specify the `DMBoundaryType` for each direction
854 . -dm_plex_sphere_radius <r>                         - The sphere radius
855 . -dm_plex_ball_radius <r>                           - Radius of the ball
856 . -dm_plex_cylinder_bd <bz>                          - Boundary type in the z direction
857 . -dm_plex_cylinder_num_wedges <n>                   - Number of wedges around the cylinder
858 . -dm_plex_reorder <order>                           - Reorder the mesh using the specified algorithm
859 . -dm_refine_pre <n>                                 - The number of refinements before distribution
860 . -dm_refine_uniform_pre <bool>                      - Flag for uniform refinement before distribution
861 . -dm_refine_volume_limit_pre <v>                    - The maximum cell volume after refinement before distribution
862 . -dm_refine <n>                                     - The number of refinements after distribution
863 . -dm_extrude <l>                                    - Activate extrusion and specify the number of layers to extrude
864 . -dm_plex_transform_extrude_thickness <t>           - The total thickness of extruded layers
865 . -dm_plex_transform_extrude_use_tensor <bool>       - Use tensor cells when extruding
866 . -dm_plex_transform_extrude_symmetric <bool>        - Extrude layers symmetrically about the surface
867 . -dm_plex_transform_extrude_normal <n0,...,nd>      - Specify the extrusion direction
868 . -dm_plex_transform_extrude_thicknesses <t0,...,tl> - Specify thickness of each layer
869 . -dm_plex_create_fv_ghost_cells                     - Flag to create finite volume ghost cells on the boundary
870 . -dm_plex_fv_ghost_cells_label <name>               - Label name for ghost cells boundary
871 . -dm_distribute <bool>                              - Flag to redistribute a mesh among processes
872 . -dm_distribute_overlap <n>                         - The size of the overlap halo
873 . -dm_plex_adj_cone <bool>                           - Set adjacency direction
874 . -dm_plex_adj_closure <bool>                        - Set adjacency size
875 . -dm_plex_use_ceed <bool>                           - Use LibCEED as the FEM backend
876 . -dm_plex_check_symmetry                            - Check that the adjacency information in the mesh is symmetric - `DMPlexCheckSymmetry()`
877 . -dm_plex_check_skeleton                            - Check that each cell has the correct number of vertices (only for homogeneous simplex or tensor meshes) - `DMPlexCheckSkeleton()`
878 . -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()`
879 . -dm_plex_check_geometry                            - Check that cells have positive volume - `DMPlexCheckGeometry()`
880 . -dm_plex_check_pointsf                             - Check some necessary conditions for `PointSF` - `DMPlexCheckPointSF()`
881 . -dm_plex_check_interface_cones                     - Check points on inter-partition interfaces have conforming order of cone points - `DMPlexCheckInterfaceCones()`
882 - -dm_plex_check_all                                 - Perform all the checks above
883 
884   Level: intermediate
885 
886   Note:
887   For some `DMType` such as `DMDA` this cannot be called after `DMSetUp()` has been called.
888 
889 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
890          `DMPlexCheckSymmetry()`, `DMPlexCheckSkeleton()`, `DMPlexCheckFaces()`, `DMPlexCheckGeometry()`, `DMPlexCheckPointSF()`, `DMPlexCheckInterfaceCones()`,
891          `DMSetOptionsPrefix()`, `DMType`, `DMPLEX`, `DMDA`, `DMSetUp()`
892 @*/
893 PetscErrorCode DMSetFromOptions(DM dm)
894 {
895   char      typeName[256];
896   PetscBool flg;
897 
898   PetscFunctionBegin;
899   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
900   dm->setfromoptionscalled = PETSC_TRUE;
901   if (dm->sf) PetscCall(PetscSFSetFromOptions(dm->sf));
902   if (dm->sectionSF) PetscCall(PetscSFSetFromOptions(dm->sectionSF));
903   if (dm->coordinates[0].dm) PetscCall(DMSetFromOptions(dm->coordinates[0].dm));
904   PetscObjectOptionsBegin((PetscObject)dm);
905   PetscCall(PetscOptionsBool("-dm_preallocate_only", "only preallocate matrix, but do not set column indices", "DMSetMatrixPreallocateOnly", dm->prealloc_only, &dm->prealloc_only, NULL));
906   PetscCall(PetscOptionsFList("-dm_vec_type", "Vector type used for created vectors", "DMSetVecType", VecList, dm->vectype, typeName, 256, &flg));
907   if (flg) PetscCall(DMSetVecType(dm, typeName));
908   PetscCall(PetscOptionsFList("-dm_mat_type", "Matrix type used for created matrices", "DMSetMatType", MatList, dm->mattype ? dm->mattype : typeName, typeName, sizeof(typeName), &flg));
909   if (flg) PetscCall(DMSetMatType(dm, typeName));
910   PetscCall(PetscOptionsEnum("-dm_blocking_type", "Topological point or field node blocking", "DMSetBlockingType", DMBlockingTypes, (PetscEnum)dm->blocking_type, (PetscEnum *)&dm->blocking_type, NULL));
911   PetscCall(PetscOptionsEnum("-dm_is_coloring_type", "Global or local coloring of Jacobian", "DMSetISColoringType", ISColoringTypes, (PetscEnum)dm->coloringtype, (PetscEnum *)&dm->coloringtype, NULL));
912   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));
913   PetscCall(PetscOptionsBool("-dm_ignore_perm_output", "Ignore the local section permutation on output", "DMGetOutputDM", dm->ignorePermOutput, &dm->ignorePermOutput, NULL));
914   PetscTryTypeMethod(dm, setfromoptions, PetscOptionsObject);
915   /* process any options handlers added with PetscObjectAddOptionsHandler() */
916   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)dm, PetscOptionsObject));
917   PetscOptionsEnd();
918   PetscFunctionReturn(PETSC_SUCCESS);
919 }
920 
921 /*@
922   DMViewFromOptions - View a `DM` in a particular way based on a request in the options database
923 
924   Collective
925 
926   Input Parameters:
927 + dm   - the `DM` object
928 . obj  - optional object that provides the prefix for the options database (if `NULL` then the prefix in obj is used)
929 - name - option string that is used to activate viewing
930 
931   Level: intermediate
932 
933   Note:
934   See `PetscObjectViewFromOptions()` for a list of values that can be provided in the options database to determine how the `DM` is viewed
935 
936 .seealso: [](ch_dmbase), `DM`, `DMView()`, `PetscObjectViewFromOptions()`, `DMCreate()`
937 @*/
938 PetscErrorCode DMViewFromOptions(DM dm, PetscObject obj, const char name[])
939 {
940   PetscFunctionBegin;
941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
942   PetscCall(PetscObjectViewFromOptions((PetscObject)dm, obj, name));
943   PetscFunctionReturn(PETSC_SUCCESS);
944 }
945 
946 /*@
947   DMView - Views a `DM`. Depending on the `PetscViewer` and its `PetscViewerFormat` it may print some ASCII information about the `DM` to the screen or a file or
948   save the `DM` in a binary file to be loaded later or create a visualization of the `DM`
949 
950   Collective
951 
952   Input Parameters:
953 + dm - the `DM` object to view
954 - v  - the viewer
955 
956   Level: beginner
957 
958   Notes:
959 
960   `PetscViewer` = `PETSCVIEWERHDF5` i.e. HDF5 format can be used with `PETSC_VIEWER_HDF5_PETSC` as the `PetscViewerFormat` to save multiple `DMPLEX`
961   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
962   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
963 
964   `PetscViewer` = `PETSCVIEWEREXODUSII` i.e. ExodusII format assumes that element blocks (mapped to "Cell sets" labels)
965   consists of sequentially numbered cells.
966 
967   If `dm` has been distributed, only the part of the `DM` on MPI rank 0 (including "ghost" cells and vertices) will be written.
968 
969   Only TRI, TET, QUAD, and HEX cells are supported.
970 
971   `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.
972   The order of the mesh shall be set using `PetscViewerExodusIISetOrder()`
973 
974   Variable names can be set and queried using `PetscViewerExodusII[Set/Get][Nodal/Zonal]VariableNames[s]`.
975 
976 .seealso: [](ch_dmbase), `DM`, `PetscViewer`, `PetscViewerFormat`, `PetscViewerSetFormat()`, `DMDestroy()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMLoad()`, `PetscObjectSetName()`
977 @*/
978 PetscErrorCode DMView(DM dm, PetscViewer v)
979 {
980   PetscBool         isbinary;
981   PetscMPIInt       size;
982   PetscViewerFormat format;
983 
984   PetscFunctionBegin;
985   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
986   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm), &v));
987   PetscValidHeaderSpecific(v, PETSC_VIEWER_CLASSID, 2);
988   /* Ideally, we would like to have this test on.
989      However, it currently breaks socket viz via GLVis.
990      During DMView(parallel_mesh,glvis_viewer), each
991      process opens a sequential ASCII socket to visualize
992      the local mesh, and PetscObjectView(dm,local_socket)
993      is internally called inside VecView_GLVis, incurring
994      in an error here */
995   /* PetscCheckSameComm(dm,1,v,2); */
996   PetscCall(PetscViewerCheckWritable(v));
997 
998   PetscCall(PetscLogEventBegin(DM_View, v, 0, 0, 0));
999   PetscCall(PetscViewerGetFormat(v, &format));
1000   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
1001   if (size == 1 && format == PETSC_VIEWER_LOAD_BALANCE) PetscFunctionReturn(PETSC_SUCCESS);
1002   PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)dm, v));
1003   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERBINARY, &isbinary));
1004   if (isbinary) {
1005     PetscInt classid = DM_FILE_CLASSID;
1006     char     type[256];
1007 
1008     PetscCall(PetscViewerBinaryWrite(v, &classid, 1, PETSC_INT));
1009     PetscCall(PetscStrncpy(type, ((PetscObject)dm)->type_name, sizeof(type)));
1010     PetscCall(PetscViewerBinaryWrite(v, type, 256, PETSC_CHAR));
1011   }
1012   PetscTryTypeMethod(dm, view, v);
1013   PetscCall(PetscLogEventEnd(DM_View, v, 0, 0, 0));
1014   PetscFunctionReturn(PETSC_SUCCESS);
1015 }
1016 
1017 /*@
1018   DMCreateGlobalVector - Creates a global vector from a `DM` object. A global vector is a parallel vector that has no duplicate values shared between MPI ranks,
1019   that is it has no ghost locations.
1020 
1021   Collective
1022 
1023   Input Parameter:
1024 . dm - the `DM` object
1025 
1026   Output Parameter:
1027 . vec - the global vector
1028 
1029   Level: beginner
1030 
1031 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateLocalVector()`, `DMGetGlobalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`,
1032          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1033 @*/
1034 PetscErrorCode DMCreateGlobalVector(DM dm, Vec *vec)
1035 {
1036   PetscFunctionBegin;
1037   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1038   PetscAssertPointer(vec, 2);
1039   PetscUseTypeMethod(dm, createglobalvector, vec);
1040   if (PetscDefined(USE_DEBUG)) {
1041     DM vdm;
1042 
1043     PetscCall(VecGetDM(*vec, &vdm));
1044     PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1045   }
1046   PetscFunctionReturn(PETSC_SUCCESS);
1047 }
1048 
1049 /*@
1050   DMCreateLocalVector - Creates a local vector from a `DM` object.
1051 
1052   Not Collective
1053 
1054   Input Parameter:
1055 . dm - the `DM` object
1056 
1057   Output Parameter:
1058 . vec - the local vector
1059 
1060   Level: beginner
1061 
1062   Note:
1063   A local vector usually has ghost locations that contain values that are owned by different MPI ranks. A global vector has no ghost locations.
1064 
1065 .seealso: [](ch_dmbase), `DM`, `Vec`, `DMCreateGlobalVector()`, `DMGetLocalVector()`, `DMDestroy()`, `DMView()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`
1066          `DMGlobalToLocalBegin()`, `DMGlobalToLocalEnd()`
1067 @*/
1068 PetscErrorCode DMCreateLocalVector(DM dm, Vec *vec)
1069 {
1070   PetscFunctionBegin;
1071   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1072   PetscAssertPointer(vec, 2);
1073   PetscUseTypeMethod(dm, createlocalvector, vec);
1074   if (PetscDefined(USE_DEBUG)) {
1075     DM vdm;
1076 
1077     PetscCall(VecGetDM(*vec, &vdm));
1078     PetscCheck(vdm, PETSC_COMM_SELF, PETSC_ERR_LIB, "DM type '%s' did not attach the DM to the vector", ((PetscObject)dm)->type_name);
1079   }
1080   PetscFunctionReturn(PETSC_SUCCESS);
1081 }
1082 
1083 /*@
1084   DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a `DM`.
1085 
1086   Collective
1087 
1088   Input Parameter:
1089 . dm - the `DM` that provides the mapping
1090 
1091   Output Parameter:
1092 . ltog - the mapping
1093 
1094   Level: advanced
1095 
1096   Notes:
1097   The global to local mapping allows one to set values into the global vector or matrix using `VecSetValuesLocal()` and `MatSetValuesLocal()`
1098 
1099   Vectors obtained with  `DMCreateGlobalVector()` and matrices obtained with `DMCreateMatrix()` already contain the global mapping so you do
1100   need to use this function with those objects.
1101 
1102   This mapping can then be used by `VecSetLocalToGlobalMapping()` or `MatSetLocalToGlobalMapping()`.
1103 
1104 .seealso: [](ch_dmbase), `DM`, `DMCreateLocalVector()`, `DMCreateGlobalVector()`, `VecSetLocalToGlobalMapping()`, `MatSetLocalToGlobalMapping()`,
1105           `DMCreateMatrix()`
1106 @*/
1107 PetscErrorCode DMGetLocalToGlobalMapping(DM dm, ISLocalToGlobalMapping *ltog)
1108 {
1109   PetscInt bs = -1, bsLocal[2], bsMinMax[2];
1110 
1111   PetscFunctionBegin;
1112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1113   PetscAssertPointer(ltog, 2);
1114   if (!dm->ltogmap) {
1115     PetscSection section, sectionGlobal;
1116 
1117     PetscCall(DMGetLocalSection(dm, &section));
1118     if (section) {
1119       const PetscInt *cdofs;
1120       PetscInt       *ltog;
1121       PetscInt        pStart, pEnd, n, p, k, l;
1122 
1123       PetscCall(DMGetGlobalSection(dm, &sectionGlobal));
1124       PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
1125       PetscCall(PetscSectionGetStorageSize(section, &n));
1126       PetscCall(PetscMalloc1(n, &ltog)); /* We want the local+overlap size */
1127       for (p = pStart, l = 0; p < pEnd; ++p) {
1128         PetscInt bdof, cdof, dof, off, c, cind;
1129 
1130         /* Should probably use constrained dofs */
1131         PetscCall(PetscSectionGetDof(section, p, &dof));
1132         PetscCall(PetscSectionGetConstraintDof(section, p, &cdof));
1133         PetscCall(PetscSectionGetConstraintIndices(section, p, &cdofs));
1134         PetscCall(PetscSectionGetOffset(sectionGlobal, p, &off));
1135         /* If you have dofs, and constraints, and they are unequal, we set the blocksize to 1 */
1136         bdof = cdof && (dof - cdof) ? 1 : dof;
1137         if (dof) bs = bs < 0 ? bdof : PetscGCD(bs, bdof);
1138 
1139         for (c = 0, cind = 0; c < dof; ++c, ++l) {
1140           if (cind < cdof && c == cdofs[cind]) {
1141             ltog[l] = off < 0 ? off - c : -(off + c + 1);
1142             cind++;
1143           } else {
1144             ltog[l] = (off < 0 ? -(off + 1) : off) + c - cind;
1145           }
1146         }
1147       }
1148       /* Must have same blocksize on all procs (some might have no points) */
1149       bsLocal[0] = bs < 0 ? PETSC_INT_MAX : bs;
1150       bsLocal[1] = bs;
1151       PetscCall(PetscGlobalMinMaxInt(PetscObjectComm((PetscObject)dm), bsLocal, bsMinMax));
1152       if (bsMinMax[0] != bsMinMax[1]) {
1153         bs = 1;
1154       } else {
1155         bs = bsMinMax[0];
1156       }
1157       bs = bs < 0 ? 1 : bs;
1158       /* Must reduce indices by blocksize */
1159       if (bs > 1) {
1160         for (l = 0, k = 0; l < n; l += bs, ++k) {
1161           // Integer division of negative values truncates toward zero(!), not toward negative infinity
1162           ltog[k] = ltog[l] >= 0 ? ltog[l] / bs : -(-(ltog[l] + 1) / bs + 1);
1163         }
1164         n /= bs;
1165       }
1166       PetscCall(ISLocalToGlobalMappingCreate(PetscObjectComm((PetscObject)dm), bs, n, ltog, PETSC_OWN_POINTER, &dm->ltogmap));
1167     } else PetscUseTypeMethod(dm, getlocaltoglobalmapping);
1168   }
1169   *ltog = dm->ltogmap;
1170   PetscFunctionReturn(PETSC_SUCCESS);
1171 }
1172 
1173 /*@
1174   DMGetBlockSize - Gets the inherent block size associated with a `DM`
1175 
1176   Not Collective
1177 
1178   Input Parameter:
1179 . dm - the `DM` with block structure
1180 
1181   Output Parameter:
1182 . bs - the block size, 1 implies no exploitable block structure
1183 
1184   Level: intermediate
1185 
1186   Notes:
1187   This might be the number of degrees of freedom at each grid point for a structured grid.
1188 
1189   Complex `DM` that represent multiphysics or staggered grids or mixed-methods do not generally have a single inherent block size, but
1190   rather different locations in the vectors may have a different block size.
1191 
1192 .seealso: [](ch_dmbase), `DM`, `ISCreateBlock()`, `VecSetBlockSize()`, `MatSetBlockSize()`, `DMGetLocalToGlobalMapping()`
1193 @*/
1194 PetscErrorCode DMGetBlockSize(DM dm, PetscInt *bs)
1195 {
1196   PetscFunctionBegin;
1197   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1198   PetscAssertPointer(bs, 2);
1199   PetscCheck(dm->bs >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM does not have enough information to provide a block size yet");
1200   *bs = dm->bs;
1201   PetscFunctionReturn(PETSC_SUCCESS);
1202 }
1203 
1204 /*@
1205   DMCreateInterpolation - Gets the interpolation matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1206   `DMCreateGlobalVector()` on the coarse `DM` to similar vectors on the fine grid `DM`.
1207 
1208   Collective
1209 
1210   Input Parameters:
1211 + dmc - the `DM` object
1212 - dmf - the second, finer `DM` object
1213 
1214   Output Parameters:
1215 + mat - the interpolation
1216 - vec - the scaling (optional, pass `NULL` if not needed), see `DMCreateInterpolationScale()`
1217 
1218   Level: developer
1219 
1220   Notes:
1221   For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1222   DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation.
1223 
1224   For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate
1225   vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
1226 
1227 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()`
1228 @*/
1229 PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec)
1230 {
1231   PetscFunctionBegin;
1232   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1233   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1234   PetscAssertPointer(mat, 3);
1235   PetscCall(PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0));
1236   PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec);
1237   PetscCall(PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0));
1238   PetscFunctionReturn(PETSC_SUCCESS);
1239 }
1240 
1241 /*@
1242   DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is
1243   the transpose of the interpolation between the `DM`.
1244 
1245   Input Parameters:
1246 + dac - `DM` that defines a coarse mesh
1247 . daf - `DM` that defines a fine mesh
1248 - mat - the restriction (or interpolation operator) from fine to coarse
1249 
1250   Output Parameter:
1251 . scale - the scaled vector
1252 
1253   Level: advanced
1254 
1255   Note:
1256   xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual)
1257   restriction. In other words xcoarse is the coarse representation of xfine.
1258 
1259   Developer Note:
1260   If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()`
1261   on the restriction/interpolation operator to set the bindingpropagates flag to true.
1262 
1263 .seealso: [](ch_dmbase), `DM`, `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, `DMCreateRestriction()`, `DMCreateGlobalVector()`
1264 @*/
1265 PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale)
1266 {
1267   Vec         fine;
1268   PetscScalar one = 1.0;
1269 #if defined(PETSC_HAVE_CUDA)
1270   PetscBool bindingpropagates, isbound;
1271 #endif
1272 
1273   PetscFunctionBegin;
1274   PetscCall(DMCreateGlobalVector(daf, &fine));
1275   PetscCall(DMCreateGlobalVector(dac, scale));
1276   PetscCall(VecSet(fine, one));
1277 #if defined(PETSC_HAVE_CUDA)
1278   /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well.
1279    * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL,
1280    * we'll need to do it for that case, too.*/
1281   PetscCall(VecGetBindingPropagates(fine, &bindingpropagates));
1282   if (bindingpropagates) {
1283     PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE));
1284     PetscCall(VecBoundToCPU(fine, &isbound));
1285     PetscCall(MatBindToCPU(mat, isbound));
1286   }
1287 #endif
1288   PetscCall(MatRestrict(mat, fine, *scale));
1289   PetscCall(VecDestroy(&fine));
1290   PetscCall(VecReciprocal(*scale));
1291   PetscFunctionReturn(PETSC_SUCCESS);
1292 }
1293 
1294 /*@
1295   DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by
1296   `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`.
1297 
1298   Collective
1299 
1300   Input Parameters:
1301 + dmc - the `DM` object
1302 - dmf - the second, finer `DM` object
1303 
1304   Output Parameter:
1305 . mat - the restriction
1306 
1307   Level: developer
1308 
1309   Note:
1310   This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that
1311   matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object.
1312 
1313 .seealso: [](ch_dmbase), `DM`, `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()`
1314 @*/
1315 PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat)
1316 {
1317   PetscFunctionBegin;
1318   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1319   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1320   PetscAssertPointer(mat, 3);
1321   PetscCall(PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0));
1322   PetscUseTypeMethod(dmc, createrestriction, dmf, mat);
1323   PetscCall(PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0));
1324   PetscFunctionReturn(PETSC_SUCCESS);
1325 }
1326 
1327 /*@
1328   DMCreateInjection - Gets injection matrix between two `DM` objects.
1329 
1330   Collective
1331 
1332   Input Parameters:
1333 + dac - the `DM` object
1334 - daf - the second, finer `DM` object
1335 
1336   Output Parameter:
1337 . mat - the injection
1338 
1339   Level: developer
1340 
1341   Notes:
1342   This is an operator that applied to a vector obtained with `DMCreateGlobalVector()` on the
1343   fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting
1344   the values on the coarse grid points. This compares to the operator obtained by
1345   `DMCreateRestriction()` or the transpose of the operator obtained by
1346   `DMCreateInterpolation()` that uses a "local weighted average" of the values around the
1347   coarse grid point as the coarse grid value.
1348 
1349   For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by
1350   `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection.
1351 
1352 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`,
1353           `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()`
1354 @*/
1355 PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat)
1356 {
1357   PetscFunctionBegin;
1358   PetscValidHeaderSpecific(dac, DM_CLASSID, 1);
1359   PetscValidHeaderSpecific(daf, DM_CLASSID, 2);
1360   PetscAssertPointer(mat, 3);
1361   PetscCall(PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0));
1362   PetscUseTypeMethod(dac, createinjection, daf, mat);
1363   PetscCall(PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0));
1364   PetscFunctionReturn(PETSC_SUCCESS);
1365 }
1366 
1367 /*@
1368   DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a
1369   a Galerkin finite element model on the `DM`
1370 
1371   Collective
1372 
1373   Input Parameters:
1374 + dmc - the target `DM` object
1375 - dmf - the source `DM` object, can be `NULL`
1376 
1377   Output Parameter:
1378 . mat - the mass matrix
1379 
1380   Level: developer
1381 
1382   Notes:
1383   For `DMPLEX` the finite element model for the `DM` must have been already provided.
1384 
1385   if `dmc` is `dmf` or `NULL`, then x^t M x is an approximation to the L2 norm of the vector x which is obtained by `DMCreateGlobalVector()`
1386 
1387 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrixLumped()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1388 @*/
1389 PetscErrorCode DMCreateMassMatrix(DM dmc, DM dmf, Mat *mat)
1390 {
1391   PetscFunctionBegin;
1392   PetscValidHeaderSpecific(dmc, DM_CLASSID, 1);
1393   if (!dmf) dmf = dmc;
1394   PetscValidHeaderSpecific(dmf, DM_CLASSID, 2);
1395   PetscAssertPointer(mat, 3);
1396   PetscCall(PetscLogEventBegin(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1397   PetscUseTypeMethod(dmc, createmassmatrix, dmf, mat);
1398   PetscCall(PetscLogEventEnd(DM_CreateMassMatrix, dmc, dmf, 0, 0));
1399   PetscFunctionReturn(PETSC_SUCCESS);
1400 }
1401 
1402 /*@
1403   DMCreateMassMatrixLumped - Gets the lumped mass matrix for a given `DM`
1404 
1405   Collective
1406 
1407   Input Parameter:
1408 . dm - the `DM` object
1409 
1410   Output Parameters:
1411 + llm - the local lumped mass matrix, which is a diagonal matrix, represented as a vector
1412 - lm  - the global lumped mass matrix, which is a diagonal matrix, represented as a vector
1413 
1414   Level: developer
1415 
1416   Note:
1417   See `DMCreateMassMatrix()` for how to create the non-lumped version of the mass matrix.
1418 
1419 .seealso: [](ch_dmbase), `DM`, `DMCreateMassMatrix()`, `DMCreateMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolation()`, `DMCreateInjection()`
1420 @*/
1421 PetscErrorCode DMCreateMassMatrixLumped(DM dm, Vec *llm, Vec *lm)
1422 {
1423   PetscFunctionBegin;
1424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1425   if (llm) PetscAssertPointer(llm, 2);
1426   if (lm) PetscAssertPointer(lm, 3);
1427   if (llm || lm) PetscUseTypeMethod(dm, createmassmatrixlumped, llm, lm);
1428   PetscFunctionReturn(PETSC_SUCCESS);
1429 }
1430 
1431 /*@
1432   DMCreateColoring - Gets coloring of a graph associated with the `DM`. Often the graph represents the operator matrix associated with the discretization
1433   of a PDE on the `DM`.
1434 
1435   Collective
1436 
1437   Input Parameters:
1438 + dm    - the `DM` object
1439 - ctype - `IS_COLORING_LOCAL` or `IS_COLORING_GLOBAL`
1440 
1441   Output Parameter:
1442 . coloring - the coloring
1443 
1444   Level: developer
1445 
1446   Notes:
1447   Coloring of matrices can also be computed directly from the sparse matrix nonzero structure via the `MatColoring` object or from the mesh from which the
1448   matrix comes from (what this function provides). In general using the mesh produces a more optimal coloring (fewer colors).
1449 
1450   This produces a coloring with the distance of 2, see `MatSetColoringDistance()` which can be used for efficiently computing Jacobians with `MatFDColoringCreate()`
1451   For `DMDA` in three dimensions with periodic boundary conditions the number of grid points in each dimension must be divisible by 2*stencil_width + 1,
1452   otherwise an error will be generated.
1453 
1454 .seealso: [](ch_dmbase), `DM`, `ISColoring`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatType()`, `MatColoring`, `MatFDColoringCreate()`
1455 @*/
1456 PetscErrorCode DMCreateColoring(DM dm, ISColoringType ctype, ISColoring *coloring)
1457 {
1458   PetscFunctionBegin;
1459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1460   PetscAssertPointer(coloring, 3);
1461   PetscUseTypeMethod(dm, getcoloring, ctype, coloring);
1462   PetscFunctionReturn(PETSC_SUCCESS);
1463 }
1464 
1465 /*@
1466   DMCreateMatrix - Gets an empty matrix for a `DM` that is most commonly used to store the Jacobian of a discrete PDE operator.
1467 
1468   Collective
1469 
1470   Input Parameter:
1471 . dm - the `DM` object
1472 
1473   Output Parameter:
1474 . mat - the empty Jacobian
1475 
1476   Options Database Key:
1477 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()` and `DMCreateMassMatrix()`, but do not fill it with zeros
1478 
1479   Level: beginner
1480 
1481   Notes:
1482   This properly preallocates the number of nonzeros in the sparse matrix so you
1483   do not need to do it yourself.
1484 
1485   By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
1486   the nonzero pattern call `DMSetMatrixPreallocateOnly()`
1487 
1488   For `DMDA`, when you call `MatView()` on this matrix it is displayed using the global natural ordering, NOT in the ordering used
1489   internally by PETSc.
1490 
1491   For `DMDA`, in general it is easiest to use `MatSetValuesStencil()` or `MatSetValuesLocal()` to put values into the matrix because
1492   `MatSetValues()` requires the indices for the global numbering for the `DMDA` which is complic`ated to compute
1493 
1494 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMSetMatType()`, `DMCreateMassMatrix()`
1495 @*/
1496 PetscErrorCode DMCreateMatrix(DM dm, Mat *mat)
1497 {
1498   PetscFunctionBegin;
1499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1500   PetscAssertPointer(mat, 2);
1501   PetscCall(MatInitializePackage());
1502   PetscCall(PetscLogEventBegin(DM_CreateMatrix, 0, 0, 0, 0));
1503   PetscUseTypeMethod(dm, creatematrix, mat);
1504   if (PetscDefined(USE_DEBUG)) {
1505     DM mdm;
1506 
1507     PetscCall(MatGetDM(*mat, &mdm));
1508     PetscCheck(mdm, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DM type '%s' did not attach the DM to the matrix", ((PetscObject)dm)->type_name);
1509   }
1510   /* Handle nullspace and near nullspace */
1511   if (dm->Nf) {
1512     MatNullSpace nullSpace;
1513     PetscInt     Nf, f;
1514 
1515     PetscCall(DMGetNumFields(dm, &Nf));
1516     for (f = 0; f < Nf; ++f) {
1517       if (dm->nullspaceConstructors[f]) {
1518         PetscCall((*dm->nullspaceConstructors[f])(dm, f, f, &nullSpace));
1519         PetscCall(MatSetNullSpace(*mat, nullSpace));
1520         PetscCall(MatNullSpaceDestroy(&nullSpace));
1521         break;
1522       }
1523     }
1524     for (f = 0; f < Nf; ++f) {
1525       if (dm->nearnullspaceConstructors[f]) {
1526         PetscCall((*dm->nearnullspaceConstructors[f])(dm, f, f, &nullSpace));
1527         PetscCall(MatSetNearNullSpace(*mat, nullSpace));
1528         PetscCall(MatNullSpaceDestroy(&nullSpace));
1529       }
1530     }
1531   }
1532   PetscCall(PetscLogEventEnd(DM_CreateMatrix, 0, 0, 0, 0));
1533   PetscFunctionReturn(PETSC_SUCCESS);
1534 }
1535 
1536 /*@
1537   DMSetMatrixPreallocateSkip - When `DMCreateMatrix()` is called the matrix sizes and
1538   `ISLocalToGlobalMapping` will be properly set, but the data structures to store values in the
1539   matrices will not be preallocated.
1540 
1541   Logically Collective
1542 
1543   Input Parameters:
1544 + dm   - the `DM`
1545 - skip - `PETSC_TRUE` to skip preallocation
1546 
1547   Level: developer
1548 
1549   Note:
1550   This is most useful to reduce initialization costs when `MatSetPreallocationCOO()` and
1551   `MatSetValuesCOO()` will be used.
1552 
1553 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateOnly()`
1554 @*/
1555 PetscErrorCode DMSetMatrixPreallocateSkip(DM dm, PetscBool skip)
1556 {
1557   PetscFunctionBegin;
1558   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1559   dm->prealloc_skip = skip;
1560   PetscFunctionReturn(PETSC_SUCCESS);
1561 }
1562 
1563 /*@
1564   DMSetMatrixPreallocateOnly - When `DMCreateMatrix()` is called the matrix will be properly
1565   preallocated but the nonzero structure and zero values will not be set.
1566 
1567   Logically Collective
1568 
1569   Input Parameters:
1570 + dm   - the `DM`
1571 - only - `PETSC_TRUE` if only want preallocation
1572 
1573   Options Database Key:
1574 . -dm_preallocate_only - Only preallocate the matrix for `DMCreateMatrix()`, `DMCreateMassMatrix()`, but do not fill it with zeros
1575 
1576   Level: developer
1577 
1578 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMSetMatrixStructureOnly()`, `DMSetMatrixPreallocateSkip()`
1579 @*/
1580 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
1581 {
1582   PetscFunctionBegin;
1583   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1584   dm->prealloc_only = only;
1585   PetscFunctionReturn(PETSC_SUCCESS);
1586 }
1587 
1588 /*@
1589   DMSetMatrixStructureOnly - When `DMCreateMatrix()` is called, the matrix nonzero structure will be created
1590   but the array for numerical values will not be allocated.
1591 
1592   Logically Collective
1593 
1594   Input Parameters:
1595 + dm   - the `DM`
1596 - only - `PETSC_TRUE` if you only want matrix nonzero structure
1597 
1598   Level: developer
1599 
1600 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `DMSetMatrixPreallocateOnly()`, `DMSetMatrixPreallocateSkip()`
1601 @*/
1602 PetscErrorCode DMSetMatrixStructureOnly(DM dm, PetscBool only)
1603 {
1604   PetscFunctionBegin;
1605   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1606   dm->structure_only = only;
1607   PetscFunctionReturn(PETSC_SUCCESS);
1608 }
1609 
1610 /*@
1611   DMSetBlockingType - set the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1612 
1613   Logically Collective
1614 
1615   Input Parameters:
1616 + dm    - the `DM`
1617 - btype - block by topological point or field node
1618 
1619   Options Database Key:
1620 . -dm_blocking_type [topological_point, field_node] - use topological point blocking or field node blocking
1621 
1622   Level: advanced
1623 
1624 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1625 @*/
1626 PetscErrorCode DMSetBlockingType(DM dm, DMBlockingType btype)
1627 {
1628   PetscFunctionBegin;
1629   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1630   dm->blocking_type = btype;
1631   PetscFunctionReturn(PETSC_SUCCESS);
1632 }
1633 
1634 /*@
1635   DMGetBlockingType - get the blocking granularity to be used for variable block size `DMCreateMatrix()` is called
1636 
1637   Not Collective
1638 
1639   Input Parameter:
1640 . dm - the `DM`
1641 
1642   Output Parameter:
1643 . btype - block by topological point or field node
1644 
1645   Level: advanced
1646 
1647 .seealso: [](ch_dmbase), `DM`, `DMCreateMatrix()`, `MatSetVariableBlockSizes()`
1648 @*/
1649 PetscErrorCode DMGetBlockingType(DM dm, DMBlockingType *btype)
1650 {
1651   PetscFunctionBegin;
1652   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1653   PetscAssertPointer(btype, 2);
1654   *btype = dm->blocking_type;
1655   PetscFunctionReturn(PETSC_SUCCESS);
1656 }
1657 
1658 /*@C
1659   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with `DMRestoreWorkArray()`
1660 
1661   Not Collective
1662 
1663   Input Parameters:
1664 + dm    - the `DM` object
1665 . count - The minimum size
1666 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, or `MPIU_INT`)
1667 
1668   Output Parameter:
1669 . mem - the work array
1670 
1671   Level: developer
1672 
1673   Notes:
1674   A `DM` may stash the array between instantiations so using this routine may be more efficient than calling `PetscMalloc()`
1675 
1676   The array may contain nonzero values
1677 
1678 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMRestoreWorkArray()`, `PetscMalloc()`
1679 @*/
1680 PetscErrorCode DMGetWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1681 {
1682   DMWorkLink  link;
1683   PetscMPIInt dsize;
1684 
1685   PetscFunctionBegin;
1686   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1687   PetscAssertPointer(mem, 4);
1688   if (!count) {
1689     *(void **)mem = NULL;
1690     PetscFunctionReturn(PETSC_SUCCESS);
1691   }
1692   if (dm->workin) {
1693     link       = dm->workin;
1694     dm->workin = dm->workin->next;
1695   } else {
1696     PetscCall(PetscNew(&link));
1697   }
1698   /* Avoid MPI_Type_size for most used datatypes
1699      Get size directly */
1700   if (dtype == MPIU_INT) dsize = sizeof(PetscInt);
1701   else if (dtype == MPIU_REAL) dsize = sizeof(PetscReal);
1702 #if defined(PETSC_USE_64BIT_INDICES)
1703   else if (dtype == MPI_INT) dsize = sizeof(int);
1704 #endif
1705 #if defined(PETSC_USE_COMPLEX)
1706   else if (dtype == MPIU_SCALAR) dsize = sizeof(PetscScalar);
1707 #endif
1708   else PetscCallMPI(MPI_Type_size(dtype, &dsize));
1709 
1710   if (((size_t)dsize * count) > link->bytes) {
1711     PetscCall(PetscFree(link->mem));
1712     PetscCall(PetscMalloc(dsize * count, &link->mem));
1713     link->bytes = dsize * count;
1714   }
1715   link->next    = dm->workout;
1716   dm->workout   = link;
1717   *(void **)mem = link->mem;
1718   PetscFunctionReturn(PETSC_SUCCESS);
1719 }
1720 
1721 /*@C
1722   DMRestoreWorkArray - Restores a work array obtained with `DMCreateWorkArray()`
1723 
1724   Not Collective
1725 
1726   Input Parameters:
1727 + dm    - the `DM` object
1728 . count - The minimum size
1729 - dtype - MPI data type, often `MPIU_REAL`, `MPIU_SCALAR`, `MPIU_INT`
1730 
1731   Output Parameter:
1732 . mem - the work array
1733 
1734   Level: developer
1735 
1736   Developer Note:
1737   count and dtype are ignored, they are only needed for `DMGetWorkArray()`
1738 
1739 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMCreate()`, `DMGetWorkArray()`
1740 @*/
1741 PetscErrorCode DMRestoreWorkArray(DM dm, PetscInt count, MPI_Datatype dtype, void *mem)
1742 {
1743   DMWorkLink *p, link;
1744 
1745   PetscFunctionBegin;
1746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
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 number 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 `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
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)
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   Notes:
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 .seealso: [](ch_dmbase), `DM`, `DMGetApplicationContext()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3736 @*/
3737 PetscErrorCode DMSetApplicationContext(DM dm, void *ctx)
3738 {
3739   PetscFunctionBegin;
3740   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3741   dm->ctx = ctx;
3742   PetscFunctionReturn(PETSC_SUCCESS);
3743 }
3744 
3745 /*@
3746   DMGetApplicationContext - Gets a user context from a `DM` object
3747 
3748   Not Collective
3749 
3750   Input Parameter:
3751 . dm - the `DM` object
3752 
3753   Output Parameter:
3754 . ctx - the user context
3755 
3756   Level: intermediate
3757 
3758   Note:
3759   A user context is a way to pass problem specific information that is accessible whenever the `DM` is available
3760 
3761 .seealso: [](ch_dmbase), `DM`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`
3762 @*/
3763 PetscErrorCode DMGetApplicationContext(DM dm, void *ctx)
3764 {
3765   PetscFunctionBegin;
3766   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3767   *(void **)ctx = dm->ctx;
3768   PetscFunctionReturn(PETSC_SUCCESS);
3769 }
3770 
3771 /*@C
3772   DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for `SNESVI`.
3773 
3774   Logically Collective
3775 
3776   Input Parameters:
3777 + dm - the DM object
3778 - f  - the function that computes variable bounds used by SNESVI (use `NULL` to cancel a previous function that was set)
3779 
3780   Level: intermediate
3781 
3782 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`,
3783          `DMSetJacobian()`
3784 @*/
3785 PetscErrorCode DMSetVariableBounds(DM dm, PetscErrorCode (*f)(DM, Vec, Vec))
3786 {
3787   PetscFunctionBegin;
3788   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3789   dm->ops->computevariablebounds = f;
3790   PetscFunctionReturn(PETSC_SUCCESS);
3791 }
3792 
3793 /*@
3794   DMHasVariableBounds - does the `DM` object have a variable bounds function?
3795 
3796   Not Collective
3797 
3798   Input Parameter:
3799 . dm - the `DM` object to destroy
3800 
3801   Output Parameter:
3802 . flg - `PETSC_TRUE` if the variable bounds function exists
3803 
3804   Level: developer
3805 
3806 .seealso: [](ch_dmbase), `DM`, `DMComputeVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3807 @*/
3808 PetscErrorCode DMHasVariableBounds(DM dm, PetscBool *flg)
3809 {
3810   PetscFunctionBegin;
3811   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3812   PetscAssertPointer(flg, 2);
3813   *flg = (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
3814   PetscFunctionReturn(PETSC_SUCCESS);
3815 }
3816 
3817 /*@
3818   DMComputeVariableBounds - compute variable bounds used by `SNESVI`.
3819 
3820   Logically Collective
3821 
3822   Input Parameter:
3823 . dm - the `DM` object
3824 
3825   Output Parameters:
3826 + xl - lower bound
3827 - xu - upper bound
3828 
3829   Level: advanced
3830 
3831   Note:
3832   This is generally not called by users. It calls the function provided by the user with DMSetVariableBounds()
3833 
3834 .seealso: [](ch_dmbase), `DM`, `DMHasVariableBounds()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateInterpolation()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMGetApplicationContext()`
3835 @*/
3836 PetscErrorCode DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
3837 {
3838   PetscFunctionBegin;
3839   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3840   PetscValidHeaderSpecific(xl, VEC_CLASSID, 2);
3841   PetscValidHeaderSpecific(xu, VEC_CLASSID, 3);
3842   PetscUseTypeMethod(dm, computevariablebounds, xl, xu);
3843   PetscFunctionReturn(PETSC_SUCCESS);
3844 }
3845 
3846 /*@
3847   DMHasColoring - does the `DM` object have a method of providing a coloring?
3848 
3849   Not Collective
3850 
3851   Input Parameter:
3852 . dm - the DM object
3853 
3854   Output Parameter:
3855 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateColoring()`.
3856 
3857   Level: developer
3858 
3859 .seealso: [](ch_dmbase), `DM`, `DMCreateColoring()`
3860 @*/
3861 PetscErrorCode DMHasColoring(DM dm, PetscBool *flg)
3862 {
3863   PetscFunctionBegin;
3864   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3865   PetscAssertPointer(flg, 2);
3866   *flg = (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
3867   PetscFunctionReturn(PETSC_SUCCESS);
3868 }
3869 
3870 /*@
3871   DMHasCreateRestriction - does the `DM` object have a method of providing a restriction?
3872 
3873   Not Collective
3874 
3875   Input Parameter:
3876 . dm - the `DM` object
3877 
3878   Output Parameter:
3879 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateRestriction()`.
3880 
3881   Level: developer
3882 
3883 .seealso: [](ch_dmbase), `DM`, `DMCreateRestriction()`, `DMHasCreateInterpolation()`, `DMHasCreateInjection()`
3884 @*/
3885 PetscErrorCode DMHasCreateRestriction(DM dm, PetscBool *flg)
3886 {
3887   PetscFunctionBegin;
3888   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3889   PetscAssertPointer(flg, 2);
3890   *flg = (dm->ops->createrestriction) ? PETSC_TRUE : PETSC_FALSE;
3891   PetscFunctionReturn(PETSC_SUCCESS);
3892 }
3893 
3894 /*@
3895   DMHasCreateInjection - does the `DM` object have a method of providing an injection?
3896 
3897   Not Collective
3898 
3899   Input Parameter:
3900 . dm - the `DM` object
3901 
3902   Output Parameter:
3903 . flg - `PETSC_TRUE` if the `DM` has facilities for `DMCreateInjection()`.
3904 
3905   Level: developer
3906 
3907 .seealso: [](ch_dmbase), `DM`, `DMCreateInjection()`, `DMHasCreateRestriction()`, `DMHasCreateInterpolation()`
3908 @*/
3909 PetscErrorCode DMHasCreateInjection(DM dm, PetscBool *flg)
3910 {
3911   PetscFunctionBegin;
3912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3913   PetscAssertPointer(flg, 2);
3914   if (dm->ops->hascreateinjection) PetscUseTypeMethod(dm, hascreateinjection, flg);
3915   else *flg = (dm->ops->createinjection) ? PETSC_TRUE : PETSC_FALSE;
3916   PetscFunctionReturn(PETSC_SUCCESS);
3917 }
3918 
3919 PetscFunctionList DMList              = NULL;
3920 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
3921 
3922 /*@
3923   DMSetType - Builds a `DM`, for a particular `DM` implementation.
3924 
3925   Collective
3926 
3927   Input Parameters:
3928 + dm     - The `DM` object
3929 - method - The name of the `DMType`, for example `DMDA`, `DMPLEX`
3930 
3931   Options Database Key:
3932 . -dm_type <type> - Sets the `DM` type; use -help for a list of available types
3933 
3934   Level: intermediate
3935 
3936   Note:
3937   Of the `DM` is constructed by directly calling a function to construct a particular `DM`, for example, `DMDACreate2d()` or `DMPlexCreateBoxMesh()`
3938 
3939 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMGetType()`, `DMCreate()`, `DMDACreate2d()`
3940 @*/
3941 PetscErrorCode DMSetType(DM dm, DMType method)
3942 {
3943   PetscErrorCode (*r)(DM);
3944   PetscBool match;
3945 
3946   PetscFunctionBegin;
3947   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3948   PetscCall(PetscObjectTypeCompare((PetscObject)dm, method, &match));
3949   if (match) PetscFunctionReturn(PETSC_SUCCESS);
3950 
3951   PetscCall(DMRegisterAll());
3952   PetscCall(PetscFunctionListFind(DMList, method, &r));
3953   PetscCheck(r, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
3954 
3955   PetscTryTypeMethod(dm, destroy);
3956   PetscCall(PetscMemzero(dm->ops, sizeof(*dm->ops)));
3957   PetscCall(PetscObjectChangeTypeName((PetscObject)dm, method));
3958   PetscCall((*r)(dm));
3959   PetscFunctionReturn(PETSC_SUCCESS);
3960 }
3961 
3962 /*@
3963   DMGetType - Gets the `DM` type name (as a string) from the `DM`.
3964 
3965   Not Collective
3966 
3967   Input Parameter:
3968 . dm - The `DM`
3969 
3970   Output Parameter:
3971 . type - The `DMType` name
3972 
3973   Level: intermediate
3974 
3975 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMDA`, `DMPLEX`, `DMSetType()`, `DMCreate()`
3976 @*/
3977 PetscErrorCode DMGetType(DM dm, DMType *type)
3978 {
3979   PetscFunctionBegin;
3980   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3981   PetscAssertPointer(type, 2);
3982   PetscCall(DMRegisterAll());
3983   *type = ((PetscObject)dm)->type_name;
3984   PetscFunctionReturn(PETSC_SUCCESS);
3985 }
3986 
3987 /*@
3988   DMConvert - Converts a `DM` to another `DM`, either of the same or different type.
3989 
3990   Collective
3991 
3992   Input Parameters:
3993 + dm      - the `DM`
3994 - newtype - new `DM` type (use "same" for the same type)
3995 
3996   Output Parameter:
3997 . M - pointer to new `DM`
3998 
3999   Level: intermediate
4000 
4001   Note:
4002   Cannot be used to convert a sequential `DM` to a parallel or a parallel to sequential,
4003   the MPI communicator of the generated `DM` is always the same as the communicator
4004   of the input `DM`.
4005 
4006 .seealso: [](ch_dmbase), `DM`, `DMSetType()`, `DMCreate()`, `DMClone()`
4007 @*/
4008 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
4009 {
4010   DM        B;
4011   char      convname[256];
4012   PetscBool sametype /*, issame */;
4013 
4014   PetscFunctionBegin;
4015   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4016   PetscValidType(dm, 1);
4017   PetscAssertPointer(M, 3);
4018   PetscCall(PetscObjectTypeCompare((PetscObject)dm, newtype, &sametype));
4019   /* PetscCall(PetscStrcmp(newtype, "same", &issame)); */
4020   if (sametype) {
4021     *M = dm;
4022     PetscCall(PetscObjectReference((PetscObject)dm));
4023     PetscFunctionReturn(PETSC_SUCCESS);
4024   } else {
4025     PetscErrorCode (*conv)(DM, DMType, DM *) = NULL;
4026 
4027     /*
4028        Order of precedence:
4029        1) See if a specialized converter is known to the current DM.
4030        2) See if a specialized converter is known to the desired DM class.
4031        3) See if a good general converter is registered for the desired class
4032        4) See if a good general converter is known for the current matrix.
4033        5) Use a really basic converter.
4034     */
4035 
4036     /* 1) See if a specialized converter is known to the current DM and the desired class */
4037     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4038     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4039     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4040     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4041     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4042     PetscCall(PetscObjectQueryFunction((PetscObject)dm, convname, &conv));
4043     if (conv) goto foundconv;
4044 
4045     /* 2)  See if a specialized converter is known to the desired DM class. */
4046     PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &B));
4047     PetscCall(DMSetType(B, newtype));
4048     PetscCall(PetscStrncpy(convname, "DMConvert_", sizeof(convname)));
4049     PetscCall(PetscStrlcat(convname, ((PetscObject)dm)->type_name, sizeof(convname)));
4050     PetscCall(PetscStrlcat(convname, "_", sizeof(convname)));
4051     PetscCall(PetscStrlcat(convname, newtype, sizeof(convname)));
4052     PetscCall(PetscStrlcat(convname, "_C", sizeof(convname)));
4053     PetscCall(PetscObjectQueryFunction((PetscObject)B, convname, &conv));
4054     if (conv) {
4055       PetscCall(DMDestroy(&B));
4056       goto foundconv;
4057     }
4058 
4059 #if 0
4060     /* 3) See if a good general converter is registered for the desired class */
4061     conv = B->ops->convertfrom;
4062     PetscCall(DMDestroy(&B));
4063     if (conv) goto foundconv;
4064 
4065     /* 4) See if a good general converter is known for the current matrix */
4066     if (dm->ops->convert) {
4067       conv = dm->ops->convert;
4068     }
4069     if (conv) goto foundconv;
4070 #endif
4071 
4072     /* 5) Use a really basic converter. */
4073     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject)dm)->type_name, newtype);
4074 
4075   foundconv:
4076     PetscCall(PetscLogEventBegin(DM_Convert, dm, 0, 0, 0));
4077     PetscCall((*conv)(dm, newtype, M));
4078     /* Things that are independent of DM type: We should consult DMClone() here */
4079     {
4080       const PetscReal *maxCell, *Lstart, *L;
4081 
4082       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
4083       PetscCall(DMSetPeriodicity(*M, maxCell, Lstart, L));
4084       (*M)->prealloc_only = dm->prealloc_only;
4085       PetscCall(PetscFree((*M)->vectype));
4086       PetscCall(PetscStrallocpy(dm->vectype, (char **)&(*M)->vectype));
4087       PetscCall(PetscFree((*M)->mattype));
4088       PetscCall(PetscStrallocpy(dm->mattype, (char **)&(*M)->mattype));
4089     }
4090     PetscCall(PetscLogEventEnd(DM_Convert, dm, 0, 0, 0));
4091   }
4092   PetscCall(PetscObjectStateIncrease((PetscObject)*M));
4093   PetscFunctionReturn(PETSC_SUCCESS);
4094 }
4095 
4096 /*--------------------------------------------------------------------------------------------------------------------*/
4097 
4098 /*@C
4099   DMRegister -  Adds a new `DM` type implementation
4100 
4101   Not Collective, No Fortran Support
4102 
4103   Input Parameters:
4104 + sname    - The name of a new user-defined creation routine
4105 - function - The creation routine itself
4106 
4107   Level: advanced
4108 
4109   Note:
4110   `DMRegister()` may be called multiple times to add several user-defined `DM`s
4111 
4112   Example Usage:
4113 .vb
4114     DMRegister("my_da", MyDMCreate);
4115 .ve
4116 
4117   Then, your `DM` type can be chosen with the procedural interface via
4118 .vb
4119     DMCreate(MPI_Comm, DM *);
4120     DMSetType(DM,"my_da");
4121 .ve
4122   or at runtime via the option
4123 .vb
4124     -da_type my_da
4125 .ve
4126 
4127 .seealso: [](ch_dmbase), `DM`, `DMType`, `DMSetType()`, `DMRegisterAll()`, `DMRegisterDestroy()`
4128 @*/
4129 PetscErrorCode DMRegister(const char sname[], PetscErrorCode (*function)(DM))
4130 {
4131   PetscFunctionBegin;
4132   PetscCall(DMInitializePackage());
4133   PetscCall(PetscFunctionListAdd(&DMList, sname, function));
4134   PetscFunctionReturn(PETSC_SUCCESS);
4135 }
4136 
4137 /*@
4138   DMLoad - Loads a DM that has been stored in binary  with `DMView()`.
4139 
4140   Collective
4141 
4142   Input Parameters:
4143 + newdm  - the newly loaded `DM`, this needs to have been created with `DMCreate()` or
4144            some related function before a call to `DMLoad()`.
4145 - viewer - binary file viewer, obtained from `PetscViewerBinaryOpen()` or
4146            `PETSCVIEWERHDF5` file viewer, obtained from `PetscViewerHDF5Open()`
4147 
4148   Level: intermediate
4149 
4150   Notes:
4151   The type is determined by the data in the file, any type set into the DM before this call is ignored.
4152 
4153   Using `PETSCVIEWERHDF5` type with `PETSC_VIEWER_HDF5_PETSC` format, one can save multiple `DMPLEX`
4154   meshes in a single HDF5 file. This in turn requires one to name the `DMPLEX` object with `PetscObjectSetName()`
4155   before saving it with `DMView()` and before loading it with `DMLoad()` for identification of the mesh object.
4156 
4157 .seealso: [](ch_dmbase), `DM`, `PetscViewerBinaryOpen()`, `DMView()`, `MatLoad()`, `VecLoad()`
4158 @*/
4159 PetscErrorCode DMLoad(DM newdm, PetscViewer viewer)
4160 {
4161   PetscBool isbinary, ishdf5;
4162 
4163   PetscFunctionBegin;
4164   PetscValidHeaderSpecific(newdm, DM_CLASSID, 1);
4165   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
4166   PetscCall(PetscViewerCheckReadable(viewer));
4167   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
4168   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
4169   PetscCall(PetscLogEventBegin(DM_Load, viewer, 0, 0, 0));
4170   if (isbinary) {
4171     PetscInt classid;
4172     char     type[256];
4173 
4174     PetscCall(PetscViewerBinaryRead(viewer, &classid, 1, NULL, PETSC_INT));
4175     PetscCheck(classid == DM_FILE_CLASSID, PetscObjectComm((PetscObject)newdm), PETSC_ERR_ARG_WRONG, "Not DM next in file, classid found %" PetscInt_FMT, classid);
4176     PetscCall(PetscViewerBinaryRead(viewer, type, 256, NULL, PETSC_CHAR));
4177     PetscCall(DMSetType(newdm, type));
4178     PetscTryTypeMethod(newdm, load, viewer);
4179   } else if (ishdf5) {
4180     PetscTryTypeMethod(newdm, load, viewer);
4181   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
4182   PetscCall(PetscLogEventEnd(DM_Load, viewer, 0, 0, 0));
4183   PetscFunctionReturn(PETSC_SUCCESS);
4184 }
4185 
4186 /* FEM Support */
4187 
4188 PetscErrorCode DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt x[])
4189 {
4190   PetscInt f;
4191 
4192   PetscFunctionBegin;
4193   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4194   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %" PetscInt_FMT " |\n", x[f]));
4195   PetscFunctionReturn(PETSC_SUCCESS);
4196 }
4197 
4198 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4199 {
4200   PetscInt f;
4201 
4202   PetscFunctionBegin;
4203   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4204   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f])));
4205   PetscFunctionReturn(PETSC_SUCCESS);
4206 }
4207 
4208 PetscErrorCode DMPrintCellVectorReal(PetscInt c, const char name[], PetscInt len, const PetscReal x[])
4209 {
4210   PetscInt f;
4211 
4212   PetscFunctionBegin;
4213   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4214   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)x[f]));
4215   PetscFunctionReturn(PETSC_SUCCESS);
4216 }
4217 
4218 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4219 {
4220   PetscInt f, g;
4221 
4222   PetscFunctionBegin;
4223   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4224   for (f = 0; f < rows; ++f) {
4225     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  |"));
4226     for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4227     PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4228   }
4229   PetscFunctionReturn(PETSC_SUCCESS);
4230 }
4231 
4232 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4233 {
4234   PetscInt           localSize, bs;
4235   PetscMPIInt        size;
4236   Vec                x, xglob;
4237   const PetscScalar *xarray;
4238 
4239   PetscFunctionBegin;
4240   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4241   PetscCall(VecDuplicate(X, &x));
4242   PetscCall(VecCopy(X, x));
4243   PetscCall(VecFilter(x, tol));
4244   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4245   if (size > 1) {
4246     PetscCall(VecGetLocalSize(x, &localSize));
4247     PetscCall(VecGetArrayRead(x, &xarray));
4248     PetscCall(VecGetBlockSize(x, &bs));
4249     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4250   } else {
4251     xglob = x;
4252   }
4253   PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4254   if (size > 1) {
4255     PetscCall(VecDestroy(&xglob));
4256     PetscCall(VecRestoreArrayRead(x, &xarray));
4257   }
4258   PetscCall(VecDestroy(&x));
4259   PetscFunctionReturn(PETSC_SUCCESS);
4260 }
4261 
4262 /*@
4263   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4264 
4265   Input Parameter:
4266 . dm - The `DM`
4267 
4268   Output Parameter:
4269 . section - The `PetscSection`
4270 
4271   Options Database Key:
4272 . -dm_petscsection_view - View the section created by the `DM`
4273 
4274   Level: intermediate
4275 
4276   Note:
4277   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4278 
4279 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4280 @*/
4281 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4282 {
4283   PetscFunctionBegin;
4284   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4285   PetscAssertPointer(section, 2);
4286   if (!dm->localSection && dm->ops->createlocalsection) {
4287     PetscInt d;
4288 
4289     if (dm->setfromoptionscalled) {
4290       PetscObject       obj = (PetscObject)dm;
4291       PetscViewer       viewer;
4292       PetscViewerFormat format;
4293       PetscBool         flg;
4294 
4295       PetscCall(PetscOptionsCreateViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4296       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4297       for (d = 0; d < dm->Nds; ++d) {
4298         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4299         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4300       }
4301       if (flg) {
4302         PetscCall(PetscViewerFlush(viewer));
4303         PetscCall(PetscViewerPopFormat(viewer));
4304         PetscCall(PetscViewerDestroy(&viewer));
4305       }
4306     }
4307     PetscUseTypeMethod(dm, createlocalsection);
4308     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4309   }
4310   *section = dm->localSection;
4311   PetscFunctionReturn(PETSC_SUCCESS);
4312 }
4313 
4314 /*@
4315   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4316 
4317   Input Parameters:
4318 + dm      - The `DM`
4319 - section - The `PetscSection`
4320 
4321   Level: intermediate
4322 
4323   Note:
4324   Any existing Section will be destroyed
4325 
4326 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4327 @*/
4328 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4329 {
4330   PetscInt numFields = 0;
4331   PetscInt f;
4332 
4333   PetscFunctionBegin;
4334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4335   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4336   PetscCall(PetscObjectReference((PetscObject)section));
4337   PetscCall(PetscSectionDestroy(&dm->localSection));
4338   dm->localSection = section;
4339   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4340   if (numFields) {
4341     PetscCall(DMSetNumFields(dm, numFields));
4342     for (f = 0; f < numFields; ++f) {
4343       PetscObject disc;
4344       const char *name;
4345 
4346       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4347       PetscCall(DMGetField(dm, f, NULL, &disc));
4348       PetscCall(PetscObjectSetName(disc, name));
4349     }
4350   }
4351   /* The global section and the SectionSF will be rebuilt
4352      in the next call to DMGetGlobalSection() and DMGetSectionSF(). */
4353   PetscCall(PetscSectionDestroy(&dm->globalSection));
4354   PetscCall(PetscSFDestroy(&dm->sectionSF));
4355   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4356 
4357   /* Clear scratch vectors */
4358   PetscCall(DMClearGlobalVectors(dm));
4359   PetscCall(DMClearLocalVectors(dm));
4360   PetscCall(DMClearNamedGlobalVectors(dm));
4361   PetscCall(DMClearNamedLocalVectors(dm));
4362   PetscFunctionReturn(PETSC_SUCCESS);
4363 }
4364 
4365 /*@C
4366   DMCreateSectionPermutation - Create a permutation of the `PetscSection` chart and optionally a block structure.
4367 
4368   Input Parameter:
4369 . dm - The `DM`
4370 
4371   Output Parameters:
4372 + perm        - A permutation of the mesh points in the chart
4373 - blockStarts - A high bit is set for the point that begins every block, or `NULL` for default blocking
4374 
4375   Level: developer
4376 
4377 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4378 @*/
4379 PetscErrorCode DMCreateSectionPermutation(DM dm, IS *perm, PetscBT *blockStarts)
4380 {
4381   PetscFunctionBegin;
4382   *perm        = NULL;
4383   *blockStarts = NULL;
4384   PetscTryTypeMethod(dm, createsectionpermutation, perm, blockStarts);
4385   PetscFunctionReturn(PETSC_SUCCESS);
4386 }
4387 
4388 /*@
4389   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4390 
4391   not Collective
4392 
4393   Input Parameter:
4394 . dm - The `DM`
4395 
4396   Output Parameters:
4397 + 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.
4398 . 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.
4399 - bias    - Vector containing bias to be added to constrained dofs
4400 
4401   Level: advanced
4402 
4403   Note:
4404   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4405 
4406 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4407 @*/
4408 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4409 {
4410   PetscFunctionBegin;
4411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4412   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4413   if (section) *section = dm->defaultConstraint.section;
4414   if (mat) *mat = dm->defaultConstraint.mat;
4415   if (bias) *bias = dm->defaultConstraint.bias;
4416   PetscFunctionReturn(PETSC_SUCCESS);
4417 }
4418 
4419 /*@
4420   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4421 
4422   Collective
4423 
4424   Input Parameters:
4425 + dm      - The `DM`
4426 . 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).
4427 . 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).
4428 - 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).
4429 
4430   Level: advanced
4431 
4432   Notes:
4433   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()`.
4434 
4435   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.
4436 
4437   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4438 
4439 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4440 @*/
4441 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4442 {
4443   PetscMPIInt result;
4444 
4445   PetscFunctionBegin;
4446   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4447   if (section) {
4448     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4449     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4450     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4451   }
4452   if (mat) {
4453     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4454     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4455     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4456   }
4457   if (bias) {
4458     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4459     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4460     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4461   }
4462   PetscCall(PetscObjectReference((PetscObject)section));
4463   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4464   dm->defaultConstraint.section = section;
4465   PetscCall(PetscObjectReference((PetscObject)mat));
4466   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4467   dm->defaultConstraint.mat = mat;
4468   PetscCall(PetscObjectReference((PetscObject)bias));
4469   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4470   dm->defaultConstraint.bias = bias;
4471   PetscFunctionReturn(PETSC_SUCCESS);
4472 }
4473 
4474 #if defined(PETSC_USE_DEBUG)
4475 /*
4476   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4477 
4478   Input Parameters:
4479 + dm - The `DM`
4480 . localSection - `PetscSection` describing the local data layout
4481 - globalSection - `PetscSection` describing the global data layout
4482 
4483   Level: intermediate
4484 
4485 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4486 */
4487 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4488 {
4489   MPI_Comm        comm;
4490   PetscLayout     layout;
4491   const PetscInt *ranges;
4492   PetscInt        pStart, pEnd, p, nroots;
4493   PetscMPIInt     size, rank;
4494   PetscBool       valid = PETSC_TRUE, gvalid;
4495 
4496   PetscFunctionBegin;
4497   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4498   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4499   PetscCallMPI(MPI_Comm_size(comm, &size));
4500   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4501   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4502   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4503   PetscCall(PetscLayoutCreate(comm, &layout));
4504   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4505   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4506   PetscCall(PetscLayoutSetUp(layout));
4507   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4508   for (p = pStart; p < pEnd; ++p) {
4509     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4510 
4511     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4512     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4513     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4514     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4515     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4516     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4517     if (!gdof) continue; /* Censored point */
4518     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4519       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4520       valid = PETSC_FALSE;
4521     }
4522     if (gcdof && (gcdof != cdof)) {
4523       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4524       valid = PETSC_FALSE;
4525     }
4526     if (gdof < 0) {
4527       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4528       for (d = 0; d < gsize; ++d) {
4529         PetscInt offset = -(goff + 1) + d, r;
4530 
4531         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4532         if (r < 0) r = -(r + 2);
4533         if ((r < 0) || (r >= size)) {
4534           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4535           valid = PETSC_FALSE;
4536           break;
4537         }
4538       }
4539     }
4540   }
4541   PetscCall(PetscLayoutDestroy(&layout));
4542   PetscCall(PetscSynchronizedFlush(comm, NULL));
4543   PetscCallMPI(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm));
4544   if (!gvalid) {
4545     PetscCall(DMView(dm, NULL));
4546     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4547   }
4548   PetscFunctionReturn(PETSC_SUCCESS);
4549 }
4550 #endif
4551 
4552 PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4553 {
4554   PetscErrorCode (*f)(DM, PetscSF *);
4555 
4556   PetscFunctionBegin;
4557   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4558   PetscAssertPointer(sf, 2);
4559   PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4560   if (f) PetscCall(f(dm, sf));
4561   else *sf = dm->sf;
4562   PetscFunctionReturn(PETSC_SUCCESS);
4563 }
4564 
4565 /*@
4566   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4567 
4568   Collective
4569 
4570   Input Parameter:
4571 . dm - The `DM`
4572 
4573   Output Parameter:
4574 . section - The `PetscSection`
4575 
4576   Level: intermediate
4577 
4578   Note:
4579   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4580 
4581 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4582 @*/
4583 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4584 {
4585   PetscFunctionBegin;
4586   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4587   PetscAssertPointer(section, 2);
4588   if (!dm->globalSection) {
4589     PetscSection s;
4590     PetscSF      sf;
4591 
4592     PetscCall(DMGetLocalSection(dm, &s));
4593     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4594     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4595     PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4596     PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4597     PetscCall(PetscLayoutDestroy(&dm->map));
4598     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4599     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4600   }
4601   *section = dm->globalSection;
4602   PetscFunctionReturn(PETSC_SUCCESS);
4603 }
4604 
4605 /*@
4606   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4607 
4608   Input Parameters:
4609 + dm      - The `DM`
4610 - section - The PetscSection, or `NULL`
4611 
4612   Level: intermediate
4613 
4614   Note:
4615   Any existing `PetscSection` will be destroyed
4616 
4617 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4618 @*/
4619 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4620 {
4621   PetscFunctionBegin;
4622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4623   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4624   PetscCall(PetscObjectReference((PetscObject)section));
4625   PetscCall(PetscSectionDestroy(&dm->globalSection));
4626   dm->globalSection = section;
4627 #if defined(PETSC_USE_DEBUG)
4628   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4629 #endif
4630   /* Clear global scratch vectors and sectionSF */
4631   PetscCall(PetscSFDestroy(&dm->sectionSF));
4632   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4633   PetscCall(DMClearGlobalVectors(dm));
4634   PetscCall(DMClearNamedGlobalVectors(dm));
4635   PetscFunctionReturn(PETSC_SUCCESS);
4636 }
4637 
4638 /*@
4639   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4640   it is created from the default `PetscSection` layouts in the `DM`.
4641 
4642   Input Parameter:
4643 . dm - The `DM`
4644 
4645   Output Parameter:
4646 . sf - The `PetscSF`
4647 
4648   Level: intermediate
4649 
4650   Note:
4651   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4652 
4653 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4654 @*/
4655 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4656 {
4657   PetscInt nroots;
4658 
4659   PetscFunctionBegin;
4660   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4661   PetscAssertPointer(sf, 2);
4662   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4663   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4664   if (nroots < 0) {
4665     PetscSection section, gSection;
4666 
4667     PetscCall(DMGetLocalSection(dm, &section));
4668     if (section) {
4669       PetscCall(DMGetGlobalSection(dm, &gSection));
4670       PetscCall(DMCreateSectionSF(dm, section, gSection));
4671     } else {
4672       *sf = NULL;
4673       PetscFunctionReturn(PETSC_SUCCESS);
4674     }
4675   }
4676   *sf = dm->sectionSF;
4677   PetscFunctionReturn(PETSC_SUCCESS);
4678 }
4679 
4680 /*@
4681   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4682 
4683   Input Parameters:
4684 + dm - The `DM`
4685 - sf - The `PetscSF`
4686 
4687   Level: intermediate
4688 
4689   Note:
4690   Any previous `PetscSF` is destroyed
4691 
4692 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4693 @*/
4694 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4695 {
4696   PetscFunctionBegin;
4697   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4698   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4699   PetscCall(PetscObjectReference((PetscObject)sf));
4700   PetscCall(PetscSFDestroy(&dm->sectionSF));
4701   dm->sectionSF = sf;
4702   PetscFunctionReturn(PETSC_SUCCESS);
4703 }
4704 
4705 /*@
4706   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4707   describing the data layout.
4708 
4709   Input Parameters:
4710 + dm            - The `DM`
4711 . localSection  - `PetscSection` describing the local data layout
4712 - globalSection - `PetscSection` describing the global data layout
4713 
4714   Level: developer
4715 
4716   Note:
4717   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4718 
4719   Developer Note:
4720   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4721   directly into the `DM`, perhaps this function should not take the local and global sections as
4722   input and should just obtain them from the `DM`? Plus PETSc creation functions return the thing
4723   they create, this returns nothing
4724 
4725 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4726 @*/
4727 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4728 {
4729   PetscFunctionBegin;
4730   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4731   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4732   PetscFunctionReturn(PETSC_SUCCESS);
4733 }
4734 
4735 /*@
4736   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4737 
4738   Not collective but the resulting `PetscSF` is collective
4739 
4740   Input Parameter:
4741 . dm - The `DM`
4742 
4743   Output Parameter:
4744 . sf - The `PetscSF`
4745 
4746   Level: intermediate
4747 
4748   Note:
4749   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4750 
4751 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4752 @*/
4753 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4754 {
4755   PetscFunctionBegin;
4756   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4757   PetscAssertPointer(sf, 2);
4758   *sf = dm->sf;
4759   PetscFunctionReturn(PETSC_SUCCESS);
4760 }
4761 
4762 /*@
4763   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4764 
4765   Collective
4766 
4767   Input Parameters:
4768 + dm - The `DM`
4769 - sf - The `PetscSF`
4770 
4771   Level: intermediate
4772 
4773 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4774 @*/
4775 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4776 {
4777   PetscFunctionBegin;
4778   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4779   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4780   PetscCall(PetscObjectReference((PetscObject)sf));
4781   PetscCall(PetscSFDestroy(&dm->sf));
4782   dm->sf = sf;
4783   PetscFunctionReturn(PETSC_SUCCESS);
4784 }
4785 
4786 /*@
4787   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4788 
4789   Input Parameter:
4790 . dm - The `DM`
4791 
4792   Output Parameter:
4793 . sf - The `PetscSF`
4794 
4795   Level: intermediate
4796 
4797   Note:
4798   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4799 
4800 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4801 @*/
4802 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4803 {
4804   PetscFunctionBegin;
4805   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4806   PetscAssertPointer(sf, 2);
4807   *sf = dm->sfNatural;
4808   PetscFunctionReturn(PETSC_SUCCESS);
4809 }
4810 
4811 /*@
4812   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4813 
4814   Input Parameters:
4815 + dm - The DM
4816 - sf - The PetscSF
4817 
4818   Level: intermediate
4819 
4820 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4821 @*/
4822 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4823 {
4824   PetscFunctionBegin;
4825   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4826   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4827   PetscCall(PetscObjectReference((PetscObject)sf));
4828   PetscCall(PetscSFDestroy(&dm->sfNatural));
4829   dm->sfNatural = sf;
4830   PetscFunctionReturn(PETSC_SUCCESS);
4831 }
4832 
4833 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4834 {
4835   PetscClassId id;
4836 
4837   PetscFunctionBegin;
4838   PetscCall(PetscObjectGetClassId(disc, &id));
4839   if (id == PETSCFE_CLASSID) {
4840     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4841   } else if (id == PETSCFV_CLASSID) {
4842     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4843   } else {
4844     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4845   }
4846   PetscFunctionReturn(PETSC_SUCCESS);
4847 }
4848 
4849 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4850 {
4851   RegionField *tmpr;
4852   PetscInt     Nf = dm->Nf, f;
4853 
4854   PetscFunctionBegin;
4855   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4856   PetscCall(PetscMalloc1(NfNew, &tmpr));
4857   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4858   for (f = Nf; f < NfNew; ++f) {
4859     tmpr[f].disc        = NULL;
4860     tmpr[f].label       = NULL;
4861     tmpr[f].avoidTensor = PETSC_FALSE;
4862   }
4863   PetscCall(PetscFree(dm->fields));
4864   dm->Nf     = NfNew;
4865   dm->fields = tmpr;
4866   PetscFunctionReturn(PETSC_SUCCESS);
4867 }
4868 
4869 /*@
4870   DMClearFields - Remove all fields from the `DM`
4871 
4872   Logically Collective
4873 
4874   Input Parameter:
4875 . dm - The `DM`
4876 
4877   Level: intermediate
4878 
4879 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4880 @*/
4881 PetscErrorCode DMClearFields(DM dm)
4882 {
4883   PetscInt f;
4884 
4885   PetscFunctionBegin;
4886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4887   for (f = 0; f < dm->Nf; ++f) {
4888     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4889     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4890   }
4891   PetscCall(PetscFree(dm->fields));
4892   dm->fields = NULL;
4893   dm->Nf     = 0;
4894   PetscFunctionReturn(PETSC_SUCCESS);
4895 }
4896 
4897 /*@
4898   DMGetNumFields - Get the number of fields in the `DM`
4899 
4900   Not Collective
4901 
4902   Input Parameter:
4903 . dm - The `DM`
4904 
4905   Output Parameter:
4906 . numFields - The number of fields
4907 
4908   Level: intermediate
4909 
4910 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4911 @*/
4912 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4913 {
4914   PetscFunctionBegin;
4915   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4916   PetscAssertPointer(numFields, 2);
4917   *numFields = dm->Nf;
4918   PetscFunctionReturn(PETSC_SUCCESS);
4919 }
4920 
4921 /*@
4922   DMSetNumFields - Set the number of fields in the `DM`
4923 
4924   Logically Collective
4925 
4926   Input Parameters:
4927 + dm        - The `DM`
4928 - numFields - The number of fields
4929 
4930   Level: intermediate
4931 
4932 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
4933 @*/
4934 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4935 {
4936   PetscInt Nf, f;
4937 
4938   PetscFunctionBegin;
4939   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4940   PetscCall(DMGetNumFields(dm, &Nf));
4941   for (f = Nf; f < numFields; ++f) {
4942     PetscContainer obj;
4943 
4944     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
4945     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
4946     PetscCall(PetscContainerDestroy(&obj));
4947   }
4948   PetscFunctionReturn(PETSC_SUCCESS);
4949 }
4950 
4951 /*@
4952   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
4953 
4954   Not Collective
4955 
4956   Input Parameters:
4957 + dm - The `DM`
4958 - f  - The field number
4959 
4960   Output Parameters:
4961 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
4962 - disc  - The discretization object (pass in `NULL` if not needed)
4963 
4964   Level: intermediate
4965 
4966 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
4967 @*/
4968 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
4969 {
4970   PetscFunctionBegin;
4971   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4972   PetscAssertPointer(disc, 4);
4973   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);
4974   if (label) *label = dm->fields[f].label;
4975   if (disc) *disc = dm->fields[f].disc;
4976   PetscFunctionReturn(PETSC_SUCCESS);
4977 }
4978 
4979 /* Does not clear the DS */
4980 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4981 {
4982   PetscFunctionBegin;
4983   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
4984   PetscCall(DMLabelDestroy(&dm->fields[f].label));
4985   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4986   dm->fields[f].label = label;
4987   dm->fields[f].disc  = disc;
4988   PetscCall(PetscObjectReference((PetscObject)label));
4989   PetscCall(PetscObjectReference(disc));
4990   PetscFunctionReturn(PETSC_SUCCESS);
4991 }
4992 
4993 /*@
4994   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
4995   the field numbering.
4996 
4997   Logically Collective
4998 
4999   Input Parameters:
5000 + dm    - The `DM`
5001 . f     - The field number
5002 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5003 - disc  - The discretization object
5004 
5005   Level: intermediate
5006 
5007 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
5008 @*/
5009 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
5010 {
5011   PetscFunctionBegin;
5012   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5013   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5014   PetscValidHeader(disc, 4);
5015   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
5016   PetscCall(DMSetField_Internal(dm, f, label, disc));
5017   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
5018   PetscCall(DMClearDS(dm));
5019   PetscFunctionReturn(PETSC_SUCCESS);
5020 }
5021 
5022 /*@
5023   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
5024   and a discretization object that defines the function space associated with those points.
5025 
5026   Logically Collective
5027 
5028   Input Parameters:
5029 + dm    - The `DM`
5030 . label - The label indicating the support of the field, or `NULL` for the entire mesh
5031 - disc  - The discretization object
5032 
5033   Level: intermediate
5034 
5035   Notes:
5036   The label already exists or will be added to the `DM` with `DMSetLabel()`.
5037 
5038   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
5039   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
5040   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
5041 
5042 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
5043 @*/
5044 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
5045 {
5046   PetscInt Nf = dm->Nf;
5047 
5048   PetscFunctionBegin;
5049   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5050   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5051   PetscValidHeader(disc, 3);
5052   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5053   dm->fields[Nf].label = label;
5054   dm->fields[Nf].disc  = disc;
5055   PetscCall(PetscObjectReference((PetscObject)label));
5056   PetscCall(PetscObjectReference(disc));
5057   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5058   PetscCall(DMClearDS(dm));
5059   PetscFunctionReturn(PETSC_SUCCESS);
5060 }
5061 
5062 /*@
5063   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5064 
5065   Logically Collective
5066 
5067   Input Parameters:
5068 + dm          - The `DM`
5069 . f           - The field index
5070 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5071 
5072   Level: intermediate
5073 
5074 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5075 @*/
5076 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5077 {
5078   PetscFunctionBegin;
5079   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);
5080   dm->fields[f].avoidTensor = avoidTensor;
5081   PetscFunctionReturn(PETSC_SUCCESS);
5082 }
5083 
5084 /*@
5085   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5086 
5087   Not Collective
5088 
5089   Input Parameters:
5090 + dm - The `DM`
5091 - f  - The field index
5092 
5093   Output Parameter:
5094 . avoidTensor - The flag to avoid defining the field on tensor cells
5095 
5096   Level: intermediate
5097 
5098 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5099 @*/
5100 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5101 {
5102   PetscFunctionBegin;
5103   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);
5104   *avoidTensor = dm->fields[f].avoidTensor;
5105   PetscFunctionReturn(PETSC_SUCCESS);
5106 }
5107 
5108 /*@
5109   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5110 
5111   Collective
5112 
5113   Input Parameters:
5114 + dm        - The `DM`
5115 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
5116 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
5117 
5118   Output Parameter:
5119 . newdm - The `DM`
5120 
5121   Level: advanced
5122 
5123 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5124 @*/
5125 PetscErrorCode DMCopyFields(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
5126 {
5127   PetscInt Nf, f;
5128 
5129   PetscFunctionBegin;
5130   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5131   PetscCall(DMGetNumFields(dm, &Nf));
5132   PetscCall(DMClearFields(newdm));
5133   for (f = 0; f < Nf; ++f) {
5134     DMLabel      label;
5135     PetscObject  field;
5136     PetscClassId id;
5137     PetscBool    useCone, useClosure;
5138 
5139     PetscCall(DMGetField(dm, f, &label, &field));
5140     PetscCall(PetscObjectGetClassId(field, &id));
5141     if (id == PETSCFE_CLASSID) {
5142       PetscFE newfe;
5143 
5144       PetscCall(PetscFELimitDegree((PetscFE)field, minDegree, maxDegree, &newfe));
5145       PetscCall(DMSetField(newdm, f, label, (PetscObject)newfe));
5146       PetscCall(PetscFEDestroy(&newfe));
5147     } else {
5148       PetscCall(DMSetField(newdm, f, label, field));
5149     }
5150     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5151     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5152   }
5153   PetscFunctionReturn(PETSC_SUCCESS);
5154 }
5155 
5156 /*@
5157   DMGetAdjacency - Returns the flags for determining variable influence
5158 
5159   Not Collective
5160 
5161   Input Parameters:
5162 + dm - The `DM` object
5163 - f  - The field number, or `PETSC_DEFAULT` for the default adjacency
5164 
5165   Output Parameters:
5166 + useCone    - Flag for variable influence starting with the cone operation
5167 - useClosure - Flag for variable influence using transitive closure
5168 
5169   Level: developer
5170 
5171   Notes:
5172 .vb
5173      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5174      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5175      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5176 .ve
5177   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5178 
5179 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5180 @*/
5181 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5182 {
5183   PetscFunctionBegin;
5184   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5185   if (useCone) PetscAssertPointer(useCone, 3);
5186   if (useClosure) PetscAssertPointer(useClosure, 4);
5187   if (f < 0) {
5188     if (useCone) *useCone = dm->adjacency[0];
5189     if (useClosure) *useClosure = dm->adjacency[1];
5190   } else {
5191     PetscInt Nf;
5192 
5193     PetscCall(DMGetNumFields(dm, &Nf));
5194     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5195     if (useCone) *useCone = dm->fields[f].adjacency[0];
5196     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5197   }
5198   PetscFunctionReturn(PETSC_SUCCESS);
5199 }
5200 
5201 /*@
5202   DMSetAdjacency - Set the flags for determining variable influence
5203 
5204   Not Collective
5205 
5206   Input Parameters:
5207 + dm         - The `DM` object
5208 . f          - The field number
5209 . useCone    - Flag for variable influence starting with the cone operation
5210 - useClosure - Flag for variable influence using transitive closure
5211 
5212   Level: developer
5213 
5214   Notes:
5215 .vb
5216      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5217      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5218      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5219 .ve
5220   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5221 
5222 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5223 @*/
5224 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5225 {
5226   PetscFunctionBegin;
5227   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5228   if (f < 0) {
5229     dm->adjacency[0] = useCone;
5230     dm->adjacency[1] = useClosure;
5231   } else {
5232     PetscInt Nf;
5233 
5234     PetscCall(DMGetNumFields(dm, &Nf));
5235     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5236     dm->fields[f].adjacency[0] = useCone;
5237     dm->fields[f].adjacency[1] = useClosure;
5238   }
5239   PetscFunctionReturn(PETSC_SUCCESS);
5240 }
5241 
5242 /*@
5243   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5244 
5245   Not collective
5246 
5247   Input Parameter:
5248 . dm - The `DM` object
5249 
5250   Output Parameters:
5251 + useCone    - Flag for variable influence starting with the cone operation
5252 - useClosure - Flag for variable influence using transitive closure
5253 
5254   Level: developer
5255 
5256   Notes:
5257 .vb
5258      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5259      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5260      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5261 .ve
5262 
5263 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5264 @*/
5265 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5266 {
5267   PetscInt Nf;
5268 
5269   PetscFunctionBegin;
5270   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5271   if (useCone) PetscAssertPointer(useCone, 2);
5272   if (useClosure) PetscAssertPointer(useClosure, 3);
5273   PetscCall(DMGetNumFields(dm, &Nf));
5274   if (!Nf) {
5275     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5276   } else {
5277     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5278   }
5279   PetscFunctionReturn(PETSC_SUCCESS);
5280 }
5281 
5282 /*@
5283   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5284 
5285   Not Collective
5286 
5287   Input Parameters:
5288 + dm         - The `DM` object
5289 . useCone    - Flag for variable influence starting with the cone operation
5290 - useClosure - Flag for variable influence using transitive closure
5291 
5292   Level: developer
5293 
5294   Notes:
5295 .vb
5296      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5297      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5298      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5299 .ve
5300 
5301 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5302 @*/
5303 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5304 {
5305   PetscInt Nf;
5306 
5307   PetscFunctionBegin;
5308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5309   PetscCall(DMGetNumFields(dm, &Nf));
5310   if (!Nf) {
5311     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5312   } else {
5313     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5314   }
5315   PetscFunctionReturn(PETSC_SUCCESS);
5316 }
5317 
5318 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5319 {
5320   DM           plex;
5321   DMLabel     *labels, *glabels;
5322   const char **names;
5323   char        *sendNames, *recvNames;
5324   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5325   size_t       len;
5326   MPI_Comm     comm;
5327   PetscMPIInt  rank, size, p, *counts, *displs;
5328 
5329   PetscFunctionBegin;
5330   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5331   PetscCallMPI(MPI_Comm_size(comm, &size));
5332   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5333   PetscCall(DMGetNumDS(dm, &Nds));
5334   for (s = 0; s < Nds; ++s) {
5335     PetscDS  dsBC;
5336     PetscInt numBd;
5337 
5338     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5339     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5340     maxLabels += numBd;
5341   }
5342   PetscCall(PetscCalloc1(maxLabels, &labels));
5343   /* Get list of labels to be completed */
5344   for (s = 0; s < Nds; ++s) {
5345     PetscDS  dsBC;
5346     PetscInt numBd, bd;
5347 
5348     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5349     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5350     for (bd = 0; bd < numBd; ++bd) {
5351       DMLabel      label;
5352       PetscInt     field;
5353       PetscObject  obj;
5354       PetscClassId id;
5355 
5356       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5357       PetscCall(DMGetField(dm, field, NULL, &obj));
5358       PetscCall(PetscObjectGetClassId(obj, &id));
5359       if (!(id == PETSCFE_CLASSID) || !label) continue;
5360       for (l = 0; l < Nl; ++l)
5361         if (labels[l] == label) break;
5362       if (l == Nl) labels[Nl++] = label;
5363     }
5364   }
5365   /* Get label names */
5366   PetscCall(PetscMalloc1(Nl, &names));
5367   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5368   for (l = 0; l < Nl; ++l) {
5369     PetscCall(PetscStrlen(names[l], &len));
5370     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5371   }
5372   PetscCall(PetscFree(labels));
5373   PetscCallMPI(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5374   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5375   for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5376   PetscCall(PetscFree(names));
5377   /* Put all names on all processes */
5378   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5379   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5380   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5381   gNl = displs[size];
5382   for (p = 0; p < size; ++p) {
5383     counts[p] *= gmaxLen;
5384     displs[p] *= gmaxLen;
5385   }
5386   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5387   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5388   PetscCall(PetscFree2(counts, displs));
5389   PetscCall(PetscFree(sendNames));
5390   for (l = 0, gl = 0; l < gNl; ++l) {
5391     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5392     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5393     for (m = 0; m < gl; ++m)
5394       if (glabels[m] == glabels[gl]) goto next_label;
5395     PetscCall(DMConvert(dm, DMPLEX, &plex));
5396     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5397     PetscCall(DMDestroy(&plex));
5398     ++gl;
5399   next_label:
5400     continue;
5401   }
5402   PetscCall(PetscFree2(recvNames, glabels));
5403   PetscFunctionReturn(PETSC_SUCCESS);
5404 }
5405 
5406 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5407 {
5408   DMSpace *tmpd;
5409   PetscInt Nds = dm->Nds, s;
5410 
5411   PetscFunctionBegin;
5412   if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5413   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5414   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5415   for (s = Nds; s < NdsNew; ++s) {
5416     tmpd[s].ds     = NULL;
5417     tmpd[s].label  = NULL;
5418     tmpd[s].fields = NULL;
5419   }
5420   PetscCall(PetscFree(dm->probs));
5421   dm->Nds   = NdsNew;
5422   dm->probs = tmpd;
5423   PetscFunctionReturn(PETSC_SUCCESS);
5424 }
5425 
5426 /*@
5427   DMGetNumDS - Get the number of discrete systems in the `DM`
5428 
5429   Not Collective
5430 
5431   Input Parameter:
5432 . dm - The `DM`
5433 
5434   Output Parameter:
5435 . Nds - The number of `PetscDS` objects
5436 
5437   Level: intermediate
5438 
5439 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5440 @*/
5441 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5442 {
5443   PetscFunctionBegin;
5444   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5445   PetscAssertPointer(Nds, 2);
5446   *Nds = dm->Nds;
5447   PetscFunctionReturn(PETSC_SUCCESS);
5448 }
5449 
5450 /*@
5451   DMClearDS - Remove all discrete systems from the `DM`
5452 
5453   Logically Collective
5454 
5455   Input Parameter:
5456 . dm - The `DM`
5457 
5458   Level: intermediate
5459 
5460 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5461 @*/
5462 PetscErrorCode DMClearDS(DM dm)
5463 {
5464   PetscInt s;
5465 
5466   PetscFunctionBegin;
5467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5468   for (s = 0; s < dm->Nds; ++s) {
5469     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5470     PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5471     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5472     PetscCall(ISDestroy(&dm->probs[s].fields));
5473   }
5474   PetscCall(PetscFree(dm->probs));
5475   dm->probs = NULL;
5476   dm->Nds   = 0;
5477   PetscFunctionReturn(PETSC_SUCCESS);
5478 }
5479 
5480 /*@
5481   DMGetDS - Get the default `PetscDS`
5482 
5483   Not Collective
5484 
5485   Input Parameter:
5486 . dm - The `DM`
5487 
5488   Output Parameter:
5489 . ds - The default `PetscDS`
5490 
5491   Level: intermediate
5492 
5493 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5494 @*/
5495 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5496 {
5497   PetscFunctionBeginHot;
5498   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5499   PetscAssertPointer(ds, 2);
5500   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5501   *ds = dm->probs[0].ds;
5502   PetscFunctionReturn(PETSC_SUCCESS);
5503 }
5504 
5505 /*@
5506   DMGetCellDS - Get the `PetscDS` defined on a given cell
5507 
5508   Not Collective
5509 
5510   Input Parameters:
5511 + dm    - The `DM`
5512 - point - Cell for the `PetscDS`
5513 
5514   Output Parameters:
5515 + ds   - The `PetscDS` defined on the given cell
5516 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds
5517 
5518   Level: developer
5519 
5520 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5521 @*/
5522 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5523 {
5524   PetscDS  dsDef = NULL;
5525   PetscInt s;
5526 
5527   PetscFunctionBeginHot;
5528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5529   if (ds) PetscAssertPointer(ds, 3);
5530   if (dsIn) PetscAssertPointer(dsIn, 4);
5531   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5532   if (ds) *ds = NULL;
5533   if (dsIn) *dsIn = NULL;
5534   for (s = 0; s < dm->Nds; ++s) {
5535     PetscInt val;
5536 
5537     if (!dm->probs[s].label) {
5538       dsDef = dm->probs[s].ds;
5539     } else {
5540       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5541       if (val >= 0) {
5542         if (ds) *ds = dm->probs[s].ds;
5543         if (dsIn) *dsIn = dm->probs[s].dsIn;
5544         break;
5545       }
5546     }
5547   }
5548   if (ds && !*ds) *ds = dsDef;
5549   PetscFunctionReturn(PETSC_SUCCESS);
5550 }
5551 
5552 /*@
5553   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5554 
5555   Not Collective
5556 
5557   Input Parameters:
5558 + dm    - The `DM`
5559 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5560 
5561   Output Parameters:
5562 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5563 . ds     - The `PetscDS` defined on the given region, or `NULL`
5564 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5565 
5566   Level: advanced
5567 
5568   Note:
5569   If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5570   the `PetscDS` for the full domain (if present) is returned. Returns with
5571   fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5572 
5573 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5574 @*/
5575 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5576 {
5577   PetscInt Nds = dm->Nds, s;
5578 
5579   PetscFunctionBegin;
5580   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5581   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5582   if (fields) {
5583     PetscAssertPointer(fields, 3);
5584     *fields = NULL;
5585   }
5586   if (ds) {
5587     PetscAssertPointer(ds, 4);
5588     *ds = NULL;
5589   }
5590   if (dsIn) {
5591     PetscAssertPointer(dsIn, 5);
5592     *dsIn = NULL;
5593   }
5594   for (s = 0; s < Nds; ++s) {
5595     if (dm->probs[s].label == label || !dm->probs[s].label) {
5596       if (fields) *fields = dm->probs[s].fields;
5597       if (ds) *ds = dm->probs[s].ds;
5598       if (dsIn) *dsIn = dm->probs[s].dsIn;
5599       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5600     }
5601   }
5602   PetscFunctionReturn(PETSC_SUCCESS);
5603 }
5604 
5605 /*@
5606   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5607 
5608   Collective
5609 
5610   Input Parameters:
5611 + dm     - The `DM`
5612 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5613 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5614 . ds     - The `PetscDS` defined on the given region
5615 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5616 
5617   Level: advanced
5618 
5619   Note:
5620   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5621   the fields argument is ignored.
5622 
5623 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5624 @*/
5625 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5626 {
5627   PetscInt Nds = dm->Nds, s;
5628 
5629   PetscFunctionBegin;
5630   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5631   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5632   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5633   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5634   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5635   for (s = 0; s < Nds; ++s) {
5636     if (dm->probs[s].label == label) {
5637       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5638       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5639       dm->probs[s].ds   = ds;
5640       dm->probs[s].dsIn = dsIn;
5641       PetscFunctionReturn(PETSC_SUCCESS);
5642     }
5643   }
5644   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5645   PetscCall(PetscObjectReference((PetscObject)label));
5646   PetscCall(PetscObjectReference((PetscObject)fields));
5647   PetscCall(PetscObjectReference((PetscObject)ds));
5648   PetscCall(PetscObjectReference((PetscObject)dsIn));
5649   if (!label) {
5650     /* Put the NULL label at the front, so it is returned as the default */
5651     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5652     Nds = 0;
5653   }
5654   dm->probs[Nds].label  = label;
5655   dm->probs[Nds].fields = fields;
5656   dm->probs[Nds].ds     = ds;
5657   dm->probs[Nds].dsIn   = dsIn;
5658   PetscFunctionReturn(PETSC_SUCCESS);
5659 }
5660 
5661 /*@
5662   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5663 
5664   Not Collective
5665 
5666   Input Parameters:
5667 + dm  - The `DM`
5668 - num - The region number, in [0, Nds)
5669 
5670   Output Parameters:
5671 + label  - The region label, or `NULL`
5672 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5673 . ds     - The `PetscDS` defined on the given region, or `NULL`
5674 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5675 
5676   Level: advanced
5677 
5678 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5679 @*/
5680 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5681 {
5682   PetscInt Nds;
5683 
5684   PetscFunctionBegin;
5685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5686   PetscCall(DMGetNumDS(dm, &Nds));
5687   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5688   if (label) {
5689     PetscAssertPointer(label, 3);
5690     *label = dm->probs[num].label;
5691   }
5692   if (fields) {
5693     PetscAssertPointer(fields, 4);
5694     *fields = dm->probs[num].fields;
5695   }
5696   if (ds) {
5697     PetscAssertPointer(ds, 5);
5698     *ds = dm->probs[num].ds;
5699   }
5700   if (dsIn) {
5701     PetscAssertPointer(dsIn, 6);
5702     *dsIn = dm->probs[num].dsIn;
5703   }
5704   PetscFunctionReturn(PETSC_SUCCESS);
5705 }
5706 
5707 /*@
5708   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5709 
5710   Not Collective
5711 
5712   Input Parameters:
5713 + dm     - The `DM`
5714 . num    - The region number, in [0, Nds)
5715 . label  - The region label, or `NULL`
5716 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5717 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5718 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5719 
5720   Level: advanced
5721 
5722 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5723 @*/
5724 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5725 {
5726   PetscInt Nds;
5727 
5728   PetscFunctionBegin;
5729   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5730   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5731   PetscCall(DMGetNumDS(dm, &Nds));
5732   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5733   PetscCall(PetscObjectReference((PetscObject)label));
5734   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5735   dm->probs[num].label = label;
5736   if (fields) {
5737     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5738     PetscCall(PetscObjectReference((PetscObject)fields));
5739     PetscCall(ISDestroy(&dm->probs[num].fields));
5740     dm->probs[num].fields = fields;
5741   }
5742   if (ds) {
5743     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5744     PetscCall(PetscObjectReference((PetscObject)ds));
5745     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5746     dm->probs[num].ds = ds;
5747   }
5748   if (dsIn) {
5749     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5750     PetscCall(PetscObjectReference((PetscObject)dsIn));
5751     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5752     dm->probs[num].dsIn = dsIn;
5753   }
5754   PetscFunctionReturn(PETSC_SUCCESS);
5755 }
5756 
5757 /*@
5758   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5759 
5760   Not Collective
5761 
5762   Input Parameters:
5763 + dm - The `DM`
5764 - ds - The `PetscDS` defined on the given region
5765 
5766   Output Parameter:
5767 . num - The region number, in [0, Nds), or -1 if not found
5768 
5769   Level: advanced
5770 
5771 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5772 @*/
5773 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5774 {
5775   PetscInt Nds, n;
5776 
5777   PetscFunctionBegin;
5778   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5779   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5780   PetscAssertPointer(num, 3);
5781   PetscCall(DMGetNumDS(dm, &Nds));
5782   for (n = 0; n < Nds; ++n)
5783     if (ds == dm->probs[n].ds) break;
5784   if (n >= Nds) *num = -1;
5785   else *num = n;
5786   PetscFunctionReturn(PETSC_SUCCESS);
5787 }
5788 
5789 /*@
5790   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5791 
5792   Not Collective
5793 
5794   Input Parameters:
5795 + dm     - The `DM`
5796 . Nc     - The number of components for the field
5797 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5798 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5799 
5800   Output Parameter:
5801 . fem - The `PetscFE`
5802 
5803   Level: intermediate
5804 
5805   Note:
5806   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5807 
5808 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5809 @*/
5810 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5811 {
5812   DMPolytopeType ct;
5813   PetscInt       dim, cStart;
5814 
5815   PetscFunctionBegin;
5816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5817   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5818   if (prefix) PetscAssertPointer(prefix, 3);
5819   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5820   PetscAssertPointer(fem, 5);
5821   PetscCall(DMGetDimension(dm, &dim));
5822   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5823   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5824   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5825   PetscFunctionReturn(PETSC_SUCCESS);
5826 }
5827 
5828 /*@
5829   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5830 
5831   Collective
5832 
5833   Input Parameter:
5834 . dm - The `DM`
5835 
5836   Options Database Key:
5837 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5838 
5839   Level: intermediate
5840 
5841 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5842 @*/
5843 PetscErrorCode DMCreateDS(DM dm)
5844 {
5845   MPI_Comm  comm;
5846   PetscDS   dsDef;
5847   DMLabel  *labelSet;
5848   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5849   PetscBool doSetup = PETSC_TRUE, flg;
5850 
5851   PetscFunctionBegin;
5852   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5853   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5854   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5855   PetscCall(DMGetCoordinateDim(dm, &dE));
5856   /* Determine how many regions we have */
5857   PetscCall(PetscMalloc1(Nf, &labelSet));
5858   Nl   = 0;
5859   Ndef = 0;
5860   for (f = 0; f < Nf; ++f) {
5861     DMLabel  label = dm->fields[f].label;
5862     PetscInt l;
5863 
5864 #ifdef PETSC_HAVE_LIBCEED
5865     /* Move CEED context to discretizations */
5866     {
5867       PetscClassId id;
5868 
5869       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5870       if (id == PETSCFE_CLASSID) {
5871         Ceed ceed;
5872 
5873         PetscCall(DMGetCeed(dm, &ceed));
5874         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5875       }
5876     }
5877 #endif
5878     if (!label) {
5879       ++Ndef;
5880       continue;
5881     }
5882     for (l = 0; l < Nl; ++l)
5883       if (label == labelSet[l]) break;
5884     if (l < Nl) continue;
5885     labelSet[Nl++] = label;
5886   }
5887   /* Create default DS if there are no labels to intersect with */
5888   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5889   if (!dsDef && Ndef && !Nl) {
5890     IS        fields;
5891     PetscInt *fld, nf;
5892 
5893     for (f = 0, nf = 0; f < Nf; ++f)
5894       if (!dm->fields[f].label) ++nf;
5895     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5896     PetscCall(PetscMalloc1(nf, &fld));
5897     for (f = 0, nf = 0; f < Nf; ++f)
5898       if (!dm->fields[f].label) fld[nf++] = f;
5899     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5900     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5901     PetscCall(ISSetType(fields, ISGENERAL));
5902     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5903 
5904     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5905     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5906     PetscCall(PetscDSDestroy(&dsDef));
5907     PetscCall(ISDestroy(&fields));
5908   }
5909   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5910   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5911   /* Intersect labels with default fields */
5912   if (Ndef && Nl) {
5913     DM              plex;
5914     DMLabel         cellLabel;
5915     IS              fieldIS, allcellIS, defcellIS = NULL;
5916     PetscInt       *fields;
5917     const PetscInt *cells;
5918     PetscInt        depth, nf = 0, n, c;
5919 
5920     PetscCall(DMConvert(dm, DMPLEX, &plex));
5921     PetscCall(DMPlexGetDepth(plex, &depth));
5922     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5923     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5924     /* TODO This looks like it only works for one label */
5925     for (l = 0; l < Nl; ++l) {
5926       DMLabel label = labelSet[l];
5927       IS      pointIS;
5928 
5929       PetscCall(ISDestroy(&defcellIS));
5930       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5931       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5932       PetscCall(ISDestroy(&pointIS));
5933     }
5934     PetscCall(ISDestroy(&allcellIS));
5935 
5936     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5937     PetscCall(ISGetLocalSize(defcellIS, &n));
5938     PetscCall(ISGetIndices(defcellIS, &cells));
5939     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5940     PetscCall(ISRestoreIndices(defcellIS, &cells));
5941     PetscCall(ISDestroy(&defcellIS));
5942     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5943 
5944     PetscCall(PetscMalloc1(Ndef, &fields));
5945     for (f = 0; f < Nf; ++f)
5946       if (!dm->fields[f].label) fields[nf++] = f;
5947     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
5948     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
5949     PetscCall(ISSetType(fieldIS, ISGENERAL));
5950     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
5951 
5952     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5953     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
5954     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5955     PetscCall(DMLabelDestroy(&cellLabel));
5956     PetscCall(PetscDSDestroy(&dsDef));
5957     PetscCall(ISDestroy(&fieldIS));
5958     PetscCall(DMDestroy(&plex));
5959   }
5960   /* Create label DSes
5961      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5962   */
5963   /* TODO Should check that labels are disjoint */
5964   for (l = 0; l < Nl; ++l) {
5965     DMLabel   label = labelSet[l];
5966     PetscDS   ds, dsIn = NULL;
5967     IS        fields;
5968     PetscInt *fld, nf;
5969 
5970     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
5971     for (f = 0, nf = 0; f < Nf; ++f)
5972       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5973     PetscCall(PetscMalloc1(nf, &fld));
5974     for (f = 0, nf = 0; f < Nf; ++f)
5975       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5976     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5977     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5978     PetscCall(ISSetType(fields, ISGENERAL));
5979     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5980     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
5981     {
5982       DMPolytopeType ct;
5983       PetscInt       lStart, lEnd;
5984       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
5985 
5986       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
5987       if (lStart >= 0) {
5988         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
5989         switch (ct) {
5990         case DM_POLYTOPE_POINT_PRISM_TENSOR:
5991         case DM_POLYTOPE_SEG_PRISM_TENSOR:
5992         case DM_POLYTOPE_TRI_PRISM_TENSOR:
5993         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5994           isCohesiveLocal = PETSC_TRUE;
5995           break;
5996         default:
5997           break;
5998         }
5999       }
6000       PetscCallMPI(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
6001       if (isCohesive) {
6002         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
6003         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
6004       }
6005       for (f = 0, nf = 0; f < Nf; ++f) {
6006         if (label == dm->fields[f].label || !dm->fields[f].label) {
6007           if (label == dm->fields[f].label) {
6008             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
6009             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
6010             if (dsIn) {
6011               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
6012               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
6013             }
6014           }
6015           ++nf;
6016         }
6017       }
6018     }
6019     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
6020     PetscCall(ISDestroy(&fields));
6021     PetscCall(PetscDSDestroy(&ds));
6022     PetscCall(PetscDSDestroy(&dsIn));
6023   }
6024   PetscCall(PetscFree(labelSet));
6025   /* Set fields in DSes */
6026   for (s = 0; s < dm->Nds; ++s) {
6027     PetscDS         ds     = dm->probs[s].ds;
6028     PetscDS         dsIn   = dm->probs[s].dsIn;
6029     IS              fields = dm->probs[s].fields;
6030     const PetscInt *fld;
6031     PetscInt        nf, dsnf;
6032     PetscBool       isCohesive;
6033 
6034     PetscCall(PetscDSGetNumFields(ds, &dsnf));
6035     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
6036     PetscCall(ISGetLocalSize(fields, &nf));
6037     PetscCall(ISGetIndices(fields, &fld));
6038     for (f = 0; f < nf; ++f) {
6039       PetscObject  disc = dm->fields[fld[f]].disc;
6040       PetscBool    isCohesiveField;
6041       PetscClassId id;
6042 
6043       /* Handle DS with no fields */
6044       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
6045       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
6046       if (isCohesive) {
6047         if (!isCohesiveField) {
6048           PetscObject bdDisc;
6049 
6050           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
6051           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
6052           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6053         } else {
6054           PetscCall(PetscDSSetDiscretization(ds, f, disc));
6055           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
6056         }
6057       } else {
6058         PetscCall(PetscDSSetDiscretization(ds, f, disc));
6059       }
6060       /* We allow people to have placeholder fields and construct the Section by hand */
6061       PetscCall(PetscObjectGetClassId(disc, &id));
6062       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
6063     }
6064     PetscCall(ISRestoreIndices(fields, &fld));
6065   }
6066   /* Allow k-jet tabulation */
6067   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6068   if (flg) {
6069     for (s = 0; s < dm->Nds; ++s) {
6070       PetscDS  ds   = dm->probs[s].ds;
6071       PetscDS  dsIn = dm->probs[s].dsIn;
6072       PetscInt Nf, f;
6073 
6074       PetscCall(PetscDSGetNumFields(ds, &Nf));
6075       for (f = 0; f < Nf; ++f) {
6076         PetscCall(PetscDSSetJetDegree(ds, f, k));
6077         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6078       }
6079     }
6080   }
6081   /* Setup DSes */
6082   if (doSetup) {
6083     for (s = 0; s < dm->Nds; ++s) {
6084       if (dm->setfromoptionscalled) {
6085         PetscCall(PetscDSSetFromOptions(dm->probs[s].ds));
6086         if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn));
6087       }
6088       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6089       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6090     }
6091   }
6092   PetscFunctionReturn(PETSC_SUCCESS);
6093 }
6094 
6095 /*@
6096   DMUseTensorOrder - Use a tensor product closure ordering for the default section
6097 
6098   Input Parameters:
6099 + dm     - The DM
6100 - tensor - Flag for tensor order
6101 
6102   Level: developer
6103 
6104 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()`
6105 @*/
6106 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor)
6107 {
6108   PetscInt  Nf;
6109   PetscBool reorder = PETSC_TRUE, isPlex;
6110 
6111   PetscFunctionBegin;
6112   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
6113   PetscCall(DMGetNumFields(dm, &Nf));
6114   for (PetscInt f = 0; f < Nf; ++f) {
6115     PetscObject  obj;
6116     PetscClassId id;
6117 
6118     PetscCall(DMGetField(dm, f, NULL, &obj));
6119     PetscCall(PetscObjectGetClassId(obj, &id));
6120     if (id == PETSCFE_CLASSID) {
6121       PetscSpace sp;
6122       PetscBool  tensor;
6123 
6124       PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp));
6125       PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor));
6126       reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE;
6127     } else reorder = PETSC_FALSE;
6128   }
6129   if (tensor) {
6130     if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL));
6131   } else {
6132     PetscSection s;
6133 
6134     PetscCall(DMGetLocalSection(dm, &s));
6135     if (s) PetscCall(PetscSectionResetClosurePermutation(s));
6136   }
6137   PetscFunctionReturn(PETSC_SUCCESS);
6138 }
6139 
6140 /*@
6141   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6142 
6143   Collective
6144 
6145   Input Parameters:
6146 + dm   - The `DM`
6147 - time - The time
6148 
6149   Output Parameters:
6150 + u   - The vector will be filled with exact solution values, or `NULL`
6151 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6152 
6153   Level: developer
6154 
6155   Note:
6156   The user must call `PetscDSSetExactSolution()` before using this routine
6157 
6158 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6159 @*/
6160 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6161 {
6162   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6163   void   **ectxs;
6164   Vec      locu, locu_t;
6165   PetscInt Nf, Nds, s;
6166 
6167   PetscFunctionBegin;
6168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6169   if (u) {
6170     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6171     PetscCall(DMGetLocalVector(dm, &locu));
6172     PetscCall(VecSet(locu, 0.));
6173   }
6174   if (u_t) {
6175     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6176     PetscCall(DMGetLocalVector(dm, &locu_t));
6177     PetscCall(VecSet(locu_t, 0.));
6178   }
6179   PetscCall(DMGetNumFields(dm, &Nf));
6180   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6181   PetscCall(DMGetNumDS(dm, &Nds));
6182   for (s = 0; s < Nds; ++s) {
6183     PetscDS         ds;
6184     DMLabel         label;
6185     IS              fieldIS;
6186     const PetscInt *fields, id = 1;
6187     PetscInt        dsNf, f;
6188 
6189     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6190     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6191     PetscCall(ISGetIndices(fieldIS, &fields));
6192     PetscCall(PetscArrayzero(exacts, Nf));
6193     PetscCall(PetscArrayzero(ectxs, Nf));
6194     if (u) {
6195       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6196       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6197       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6198     }
6199     if (u_t) {
6200       PetscCall(PetscArrayzero(exacts, Nf));
6201       PetscCall(PetscArrayzero(ectxs, Nf));
6202       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6203       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6204       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6205     }
6206     PetscCall(ISRestoreIndices(fieldIS, &fields));
6207   }
6208   if (u) {
6209     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6210     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6211   }
6212   if (u_t) {
6213     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6214     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6215   }
6216   PetscCall(PetscFree2(exacts, ectxs));
6217   if (u) {
6218     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6219     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6220     PetscCall(DMRestoreLocalVector(dm, &locu));
6221   }
6222   if (u_t) {
6223     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6224     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6225     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6226   }
6227   PetscFunctionReturn(PETSC_SUCCESS);
6228 }
6229 
6230 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscInt minDegree, PetscInt maxDegree, PetscDS ds, PetscDS dsIn)
6231 {
6232   PetscDS dsNew, dsInNew = NULL;
6233 
6234   PetscFunctionBegin;
6235   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6236   PetscCall(PetscDSCopy(ds, minDegree, maxDegree, dm, dsNew));
6237   if (dsIn) {
6238     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6239     PetscCall(PetscDSCopy(dsIn, minDegree, maxDegree, dm, dsInNew));
6240   }
6241   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6242   PetscCall(PetscDSDestroy(&dsNew));
6243   PetscCall(PetscDSDestroy(&dsInNew));
6244   PetscFunctionReturn(PETSC_SUCCESS);
6245 }
6246 
6247 /*@
6248   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6249 
6250   Collective
6251 
6252   Input Parameters:
6253 + dm        - The `DM`
6254 . minDegree - Minimum degree for a discretization, or `PETSC_DETERMINE` for no limit
6255 - maxDegree - Maximum degree for a discretization, or `PETSC_DETERMINE` for no limit
6256 
6257   Output Parameter:
6258 . newdm - The `DM`
6259 
6260   Level: advanced
6261 
6262 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6263 @*/
6264 PetscErrorCode DMCopyDS(DM dm, PetscInt minDegree, PetscInt maxDegree, DM newdm)
6265 {
6266   PetscInt Nds, s;
6267 
6268   PetscFunctionBegin;
6269   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6270   PetscCall(DMGetNumDS(dm, &Nds));
6271   PetscCall(DMClearDS(newdm));
6272   for (s = 0; s < Nds; ++s) {
6273     DMLabel  label;
6274     IS       fields;
6275     PetscDS  ds, dsIn, newds;
6276     PetscInt Nbd, bd;
6277 
6278     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6279     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6280     PetscCall(DMTransferDS_Internal(newdm, label, fields, minDegree, maxDegree, ds, dsIn));
6281     /* Complete new labels in the new DS */
6282     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6283     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6284     for (bd = 0; bd < Nbd; ++bd) {
6285       PetscWeakForm wf;
6286       DMLabel       label;
6287       PetscInt      field;
6288 
6289       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6290       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6291     }
6292   }
6293   PetscCall(DMCompleteBCLabels_Internal(newdm));
6294   PetscFunctionReturn(PETSC_SUCCESS);
6295 }
6296 
6297 /*@
6298   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6299 
6300   Collective
6301 
6302   Input Parameter:
6303 . dm - The `DM`
6304 
6305   Output Parameter:
6306 . newdm - The `DM`
6307 
6308   Level: advanced
6309 
6310   Developer Note:
6311   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6312 
6313 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6314 @*/
6315 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6316 {
6317   PetscFunctionBegin;
6318   PetscCall(DMCopyFields(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6319   PetscCall(DMCopyDS(dm, PETSC_DETERMINE, PETSC_DETERMINE, newdm));
6320   PetscFunctionReturn(PETSC_SUCCESS);
6321 }
6322 
6323 /*@
6324   DMGetDimension - Return the topological dimension of the `DM`
6325 
6326   Not Collective
6327 
6328   Input Parameter:
6329 . dm - The `DM`
6330 
6331   Output Parameter:
6332 . dim - The topological dimension
6333 
6334   Level: beginner
6335 
6336 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6337 @*/
6338 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6339 {
6340   PetscFunctionBegin;
6341   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6342   PetscAssertPointer(dim, 2);
6343   *dim = dm->dim;
6344   PetscFunctionReturn(PETSC_SUCCESS);
6345 }
6346 
6347 /*@
6348   DMSetDimension - Set the topological dimension of the `DM`
6349 
6350   Collective
6351 
6352   Input Parameters:
6353 + dm  - The `DM`
6354 - dim - The topological dimension
6355 
6356   Level: beginner
6357 
6358 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6359 @*/
6360 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6361 {
6362   PetscDS  ds;
6363   PetscInt Nds, n;
6364 
6365   PetscFunctionBegin;
6366   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6367   PetscValidLogicalCollectiveInt(dm, dim, 2);
6368   dm->dim = dim;
6369   if (dm->dim >= 0) {
6370     PetscCall(DMGetNumDS(dm, &Nds));
6371     for (n = 0; n < Nds; ++n) {
6372       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6373       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6374     }
6375   }
6376   PetscFunctionReturn(PETSC_SUCCESS);
6377 }
6378 
6379 /*@
6380   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6381 
6382   Collective
6383 
6384   Input Parameters:
6385 + dm  - the `DM`
6386 - dim - the dimension
6387 
6388   Output Parameters:
6389 + pStart - The first point of the given dimension
6390 - pEnd   - The first point following points of the given dimension
6391 
6392   Level: intermediate
6393 
6394   Note:
6395   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6396   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6397   then the interval is empty.
6398 
6399 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6400 @*/
6401 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6402 {
6403   PetscInt d;
6404 
6405   PetscFunctionBegin;
6406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6407   PetscCall(DMGetDimension(dm, &d));
6408   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6409   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6410   PetscFunctionReturn(PETSC_SUCCESS);
6411 }
6412 
6413 /*@
6414   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6415 
6416   Collective
6417 
6418   Input Parameter:
6419 . dm - The original `DM`
6420 
6421   Output Parameter:
6422 . odm - The `DM` which provides the layout for output
6423 
6424   Level: intermediate
6425 
6426   Note:
6427   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6428   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6429   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6430 
6431 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6432 @*/
6433 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6434 {
6435   PetscSection section;
6436   IS           perm;
6437   PetscBool    hasConstraints, newDM, gnewDM;
6438   PetscInt     num_face_sfs = 0;
6439 
6440   PetscFunctionBegin;
6441   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6442   PetscAssertPointer(odm, 2);
6443   PetscCall(DMGetLocalSection(dm, &section));
6444   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6445   PetscCall(PetscSectionGetPermutation(section, &perm));
6446   PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, NULL));
6447   newDM = hasConstraints || perm || (num_face_sfs > 0) ? PETSC_TRUE : PETSC_FALSE;
6448   PetscCallMPI(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6449   if (!gnewDM) {
6450     *odm = dm;
6451     PetscFunctionReturn(PETSC_SUCCESS);
6452   }
6453   if (!dm->dmBC) {
6454     PetscSection newSection, gsection;
6455     PetscSF      sf, sfNatural;
6456     PetscBool    usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE;
6457 
6458     PetscCall(DMClone(dm, &dm->dmBC));
6459     PetscCall(DMCopyDisc(dm, dm->dmBC));
6460     PetscCall(PetscSectionClone(section, &newSection));
6461     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6462     PetscCall(PetscSectionDestroy(&newSection));
6463     PetscCall(DMGetNaturalSF(dm, &sfNatural));
6464     PetscCall(DMSetNaturalSF(dm->dmBC, sfNatural));
6465     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6466     PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection));
6467     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6468     PetscCall(PetscSectionDestroy(&gsection));
6469   }
6470   *odm = dm->dmBC;
6471   PetscFunctionReturn(PETSC_SUCCESS);
6472 }
6473 
6474 /*@
6475   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6476 
6477   Input Parameter:
6478 . dm - The original `DM`
6479 
6480   Output Parameters:
6481 + num - The output sequence number
6482 - val - The output sequence value
6483 
6484   Level: intermediate
6485 
6486   Note:
6487   This is intended for output that should appear in sequence, for instance
6488   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6489 
6490   Developer Note:
6491   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6492   not directly related to the `DM`.
6493 
6494 .seealso: [](ch_dmbase), `DM`, `VecView()`
6495 @*/
6496 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6497 {
6498   PetscFunctionBegin;
6499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6500   if (num) {
6501     PetscAssertPointer(num, 2);
6502     *num = dm->outputSequenceNum;
6503   }
6504   if (val) {
6505     PetscAssertPointer(val, 3);
6506     *val = dm->outputSequenceVal;
6507   }
6508   PetscFunctionReturn(PETSC_SUCCESS);
6509 }
6510 
6511 /*@
6512   DMSetOutputSequenceNumber - Set the sequence number/value for output
6513 
6514   Input Parameters:
6515 + dm  - The original `DM`
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 .seealso: [](ch_dmbase), `DM`, `VecView()`
6526 @*/
6527 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6528 {
6529   PetscFunctionBegin;
6530   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6531   dm->outputSequenceNum = num;
6532   dm->outputSequenceVal = val;
6533   PetscFunctionReturn(PETSC_SUCCESS);
6534 }
6535 
6536 /*@
6537   DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6538 
6539   Input Parameters:
6540 + dm     - The original `DM`
6541 . viewer - The `PetscViewer` to get it from
6542 . name   - The sequence name
6543 - num    - The output sequence number
6544 
6545   Output Parameter:
6546 . val - The output sequence value
6547 
6548   Level: intermediate
6549 
6550   Note:
6551   This is intended for output that should appear in sequence, for instance
6552   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6553 
6554   Developer Note:
6555   It is unclear at the user API level why a `DM` is needed as input
6556 
6557 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6558 @*/
6559 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char name[], PetscInt num, PetscReal *val)
6560 {
6561   PetscBool ishdf5;
6562 
6563   PetscFunctionBegin;
6564   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6565   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6566   PetscAssertPointer(name, 3);
6567   PetscAssertPointer(val, 5);
6568   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6569   if (ishdf5) {
6570 #if defined(PETSC_HAVE_HDF5)
6571     PetscScalar value;
6572 
6573     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6574     *val = PetscRealPart(value);
6575 #endif
6576   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6577   PetscFunctionReturn(PETSC_SUCCESS);
6578 }
6579 
6580 /*@
6581   DMGetOutputSequenceLength - Retrieve the number of sequence values from a `PetscViewer`
6582 
6583   Input Parameters:
6584 + dm     - The original `DM`
6585 . viewer - The `PetscViewer` to get it from
6586 - name   - The sequence name
6587 
6588   Output Parameter:
6589 . len - The length of the output sequence
6590 
6591   Level: intermediate
6592 
6593   Note:
6594   This is intended for output that should appear in sequence, for instance
6595   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6596 
6597   Developer Note:
6598   It is unclear at the user API level why a `DM` is needed as input
6599 
6600 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6601 @*/
6602 PetscErrorCode DMGetOutputSequenceLength(DM dm, PetscViewer viewer, const char name[], PetscInt *len)
6603 {
6604   PetscBool ishdf5;
6605 
6606   PetscFunctionBegin;
6607   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6608   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6609   PetscAssertPointer(name, 3);
6610   PetscAssertPointer(len, 4);
6611   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6612   if (ishdf5) {
6613 #if defined(PETSC_HAVE_HDF5)
6614     PetscCall(DMSequenceGetLength_HDF5_Internal(dm, name, len, viewer));
6615 #endif
6616   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6617   PetscFunctionReturn(PETSC_SUCCESS);
6618 }
6619 
6620 /*@
6621   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6622 
6623   Not Collective
6624 
6625   Input Parameter:
6626 . dm - The `DM`
6627 
6628   Output Parameter:
6629 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6630 
6631   Level: beginner
6632 
6633 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6634 @*/
6635 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6636 {
6637   PetscFunctionBegin;
6638   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6639   PetscAssertPointer(useNatural, 2);
6640   *useNatural = dm->useNatural;
6641   PetscFunctionReturn(PETSC_SUCCESS);
6642 }
6643 
6644 /*@
6645   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6646 
6647   Collective
6648 
6649   Input Parameters:
6650 + dm         - The `DM`
6651 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6652 
6653   Level: beginner
6654 
6655   Note:
6656   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6657 
6658 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6659 @*/
6660 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6661 {
6662   PetscFunctionBegin;
6663   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6664   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6665   dm->useNatural = useNatural;
6666   PetscFunctionReturn(PETSC_SUCCESS);
6667 }
6668 
6669 /*@
6670   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6671 
6672   Not Collective
6673 
6674   Input Parameters:
6675 + dm   - The `DM` object
6676 - name - The label name
6677 
6678   Level: intermediate
6679 
6680 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6681 @*/
6682 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6683 {
6684   PetscBool flg;
6685   DMLabel   label;
6686 
6687   PetscFunctionBegin;
6688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6689   PetscAssertPointer(name, 2);
6690   PetscCall(DMHasLabel(dm, name, &flg));
6691   if (!flg) {
6692     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6693     PetscCall(DMAddLabel(dm, label));
6694     PetscCall(DMLabelDestroy(&label));
6695   }
6696   PetscFunctionReturn(PETSC_SUCCESS);
6697 }
6698 
6699 /*@
6700   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6701 
6702   Not Collective
6703 
6704   Input Parameters:
6705 + dm   - The `DM` object
6706 . l    - The index for the label
6707 - name - The label name
6708 
6709   Level: intermediate
6710 
6711 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6712 @*/
6713 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6714 {
6715   DMLabelLink orig, prev = NULL;
6716   DMLabel     label;
6717   PetscInt    Nl, m;
6718   PetscBool   flg, match;
6719   const char *lname;
6720 
6721   PetscFunctionBegin;
6722   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6723   PetscAssertPointer(name, 3);
6724   PetscCall(DMHasLabel(dm, name, &flg));
6725   if (!flg) {
6726     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6727     PetscCall(DMAddLabel(dm, label));
6728     PetscCall(DMLabelDestroy(&label));
6729   }
6730   PetscCall(DMGetNumLabels(dm, &Nl));
6731   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6732   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6733     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6734     PetscCall(PetscStrcmp(name, lname, &match));
6735     if (match) break;
6736   }
6737   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6738   if (!m) dm->labels = orig->next;
6739   else prev->next = orig->next;
6740   if (!l) {
6741     orig->next = dm->labels;
6742     dm->labels = orig;
6743   } else {
6744     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next);
6745     orig->next = prev->next;
6746     prev->next = orig;
6747   }
6748   PetscFunctionReturn(PETSC_SUCCESS);
6749 }
6750 
6751 /*@
6752   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6753 
6754   Not Collective
6755 
6756   Input Parameters:
6757 + dm    - The `DM` object
6758 . name  - The label name
6759 - point - The mesh point
6760 
6761   Output Parameter:
6762 . value - The label value for this point, or -1 if the point is not in the label
6763 
6764   Level: beginner
6765 
6766 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6767 @*/
6768 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6769 {
6770   DMLabel label;
6771 
6772   PetscFunctionBegin;
6773   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6774   PetscAssertPointer(name, 2);
6775   PetscCall(DMGetLabel(dm, name, &label));
6776   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6777   PetscCall(DMLabelGetValue(label, point, value));
6778   PetscFunctionReturn(PETSC_SUCCESS);
6779 }
6780 
6781 /*@
6782   DMSetLabelValue - Add a point to a `DMLabel` with given value
6783 
6784   Not Collective
6785 
6786   Input Parameters:
6787 + dm    - The `DM` object
6788 . name  - The label name
6789 . point - The mesh point
6790 - value - The label value for this point
6791 
6792   Output Parameter:
6793 
6794   Level: beginner
6795 
6796 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6797 @*/
6798 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6799 {
6800   DMLabel label;
6801 
6802   PetscFunctionBegin;
6803   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6804   PetscAssertPointer(name, 2);
6805   PetscCall(DMGetLabel(dm, name, &label));
6806   if (!label) {
6807     PetscCall(DMCreateLabel(dm, name));
6808     PetscCall(DMGetLabel(dm, name, &label));
6809   }
6810   PetscCall(DMLabelSetValue(label, point, value));
6811   PetscFunctionReturn(PETSC_SUCCESS);
6812 }
6813 
6814 /*@
6815   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6816 
6817   Not Collective
6818 
6819   Input Parameters:
6820 + dm    - The `DM` object
6821 . name  - The label name
6822 . point - The mesh point
6823 - value - The label value for this point
6824 
6825   Level: beginner
6826 
6827 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6828 @*/
6829 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6830 {
6831   DMLabel label;
6832 
6833   PetscFunctionBegin;
6834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6835   PetscAssertPointer(name, 2);
6836   PetscCall(DMGetLabel(dm, name, &label));
6837   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6838   PetscCall(DMLabelClearValue(label, point, value));
6839   PetscFunctionReturn(PETSC_SUCCESS);
6840 }
6841 
6842 /*@
6843   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6844 
6845   Not Collective
6846 
6847   Input Parameters:
6848 + dm   - The `DM` object
6849 - name - The label name
6850 
6851   Output Parameter:
6852 . size - The number of different integer ids, or 0 if the label does not exist
6853 
6854   Level: beginner
6855 
6856   Developer Note:
6857   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6858 
6859 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6860 @*/
6861 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6862 {
6863   DMLabel label;
6864 
6865   PetscFunctionBegin;
6866   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6867   PetscAssertPointer(name, 2);
6868   PetscAssertPointer(size, 3);
6869   PetscCall(DMGetLabel(dm, name, &label));
6870   *size = 0;
6871   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6872   PetscCall(DMLabelGetNumValues(label, size));
6873   PetscFunctionReturn(PETSC_SUCCESS);
6874 }
6875 
6876 /*@
6877   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6878 
6879   Not Collective
6880 
6881   Input Parameters:
6882 + dm   - The `DM` object
6883 - name - The label name
6884 
6885   Output Parameter:
6886 . ids - The integer ids, or `NULL` if the label does not exist
6887 
6888   Level: beginner
6889 
6890 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6891 @*/
6892 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6893 {
6894   DMLabel label;
6895 
6896   PetscFunctionBegin;
6897   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6898   PetscAssertPointer(name, 2);
6899   PetscAssertPointer(ids, 3);
6900   PetscCall(DMGetLabel(dm, name, &label));
6901   *ids = NULL;
6902   if (label) {
6903     PetscCall(DMLabelGetValueIS(label, ids));
6904   } else {
6905     /* returning an empty IS */
6906     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6907   }
6908   PetscFunctionReturn(PETSC_SUCCESS);
6909 }
6910 
6911 /*@
6912   DMGetStratumSize - Get the number of points in a label stratum
6913 
6914   Not Collective
6915 
6916   Input Parameters:
6917 + dm    - The `DM` object
6918 . name  - The label name of the stratum
6919 - value - The stratum value
6920 
6921   Output Parameter:
6922 . size - The number of points, also called the stratum size
6923 
6924   Level: beginner
6925 
6926 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6927 @*/
6928 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6929 {
6930   DMLabel label;
6931 
6932   PetscFunctionBegin;
6933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6934   PetscAssertPointer(name, 2);
6935   PetscAssertPointer(size, 4);
6936   PetscCall(DMGetLabel(dm, name, &label));
6937   *size = 0;
6938   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6939   PetscCall(DMLabelGetStratumSize(label, value, size));
6940   PetscFunctionReturn(PETSC_SUCCESS);
6941 }
6942 
6943 /*@
6944   DMGetStratumIS - Get the points in a label stratum
6945 
6946   Not Collective
6947 
6948   Input Parameters:
6949 + dm    - The `DM` object
6950 . name  - The label name
6951 - value - The stratum value
6952 
6953   Output Parameter:
6954 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
6955 
6956   Level: beginner
6957 
6958 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6959 @*/
6960 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6961 {
6962   DMLabel label;
6963 
6964   PetscFunctionBegin;
6965   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6966   PetscAssertPointer(name, 2);
6967   PetscAssertPointer(points, 4);
6968   PetscCall(DMGetLabel(dm, name, &label));
6969   *points = NULL;
6970   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6971   PetscCall(DMLabelGetStratumIS(label, value, points));
6972   PetscFunctionReturn(PETSC_SUCCESS);
6973 }
6974 
6975 /*@
6976   DMSetStratumIS - Set the points in a label stratum
6977 
6978   Not Collective
6979 
6980   Input Parameters:
6981 + dm     - The `DM` object
6982 . name   - The label name
6983 . value  - The stratum value
6984 - points - The stratum points
6985 
6986   Level: beginner
6987 
6988 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
6989 @*/
6990 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6991 {
6992   DMLabel label;
6993 
6994   PetscFunctionBegin;
6995   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6996   PetscAssertPointer(name, 2);
6997   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
6998   PetscCall(DMGetLabel(dm, name, &label));
6999   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7000   PetscCall(DMLabelSetStratumIS(label, value, points));
7001   PetscFunctionReturn(PETSC_SUCCESS);
7002 }
7003 
7004 /*@
7005   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
7006 
7007   Not Collective
7008 
7009   Input Parameters:
7010 + dm    - The `DM` object
7011 . name  - The label name
7012 - value - The label value for this point
7013 
7014   Output Parameter:
7015 
7016   Level: beginner
7017 
7018 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7019 @*/
7020 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7021 {
7022   DMLabel label;
7023 
7024   PetscFunctionBegin;
7025   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7026   PetscAssertPointer(name, 2);
7027   PetscCall(DMGetLabel(dm, name, &label));
7028   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
7029   PetscCall(DMLabelClearStratum(label, value));
7030   PetscFunctionReturn(PETSC_SUCCESS);
7031 }
7032 
7033 /*@
7034   DMGetNumLabels - Return the number of labels defined by on the `DM`
7035 
7036   Not Collective
7037 
7038   Input Parameter:
7039 . dm - The `DM` object
7040 
7041   Output Parameter:
7042 . numLabels - the number of Labels
7043 
7044   Level: intermediate
7045 
7046 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7047 @*/
7048 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7049 {
7050   DMLabelLink next = dm->labels;
7051   PetscInt    n    = 0;
7052 
7053   PetscFunctionBegin;
7054   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7055   PetscAssertPointer(numLabels, 2);
7056   while (next) {
7057     ++n;
7058     next = next->next;
7059   }
7060   *numLabels = n;
7061   PetscFunctionReturn(PETSC_SUCCESS);
7062 }
7063 
7064 /*@
7065   DMGetLabelName - Return the name of nth label
7066 
7067   Not Collective
7068 
7069   Input Parameters:
7070 + dm - The `DM` object
7071 - n  - the label number
7072 
7073   Output Parameter:
7074 . name - the label name
7075 
7076   Level: intermediate
7077 
7078   Developer Note:
7079   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
7080 
7081 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7082 @*/
7083 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char *name[])
7084 {
7085   DMLabelLink next = dm->labels;
7086   PetscInt    l    = 0;
7087 
7088   PetscFunctionBegin;
7089   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7090   PetscAssertPointer(name, 3);
7091   while (next) {
7092     if (l == n) {
7093       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
7094       PetscFunctionReturn(PETSC_SUCCESS);
7095     }
7096     ++l;
7097     next = next->next;
7098   }
7099   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7100 }
7101 
7102 /*@
7103   DMHasLabel - Determine whether the `DM` has a label of a given name
7104 
7105   Not Collective
7106 
7107   Input Parameters:
7108 + dm   - The `DM` object
7109 - name - The label name
7110 
7111   Output Parameter:
7112 . hasLabel - `PETSC_TRUE` if the label is present
7113 
7114   Level: intermediate
7115 
7116 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7117 @*/
7118 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7119 {
7120   DMLabelLink next = dm->labels;
7121   const char *lname;
7122 
7123   PetscFunctionBegin;
7124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7125   PetscAssertPointer(name, 2);
7126   PetscAssertPointer(hasLabel, 3);
7127   *hasLabel = PETSC_FALSE;
7128   while (next) {
7129     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7130     PetscCall(PetscStrcmp(name, lname, hasLabel));
7131     if (*hasLabel) break;
7132     next = next->next;
7133   }
7134   PetscFunctionReturn(PETSC_SUCCESS);
7135 }
7136 
7137 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7138 /*@
7139   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
7140 
7141   Not Collective
7142 
7143   Input Parameters:
7144 + dm   - The `DM` object
7145 - name - The label name
7146 
7147   Output Parameter:
7148 . label - The `DMLabel`, or `NULL` if the label is absent
7149 
7150   Default labels in a `DMPLEX`:
7151 + "depth"       - Holds the depth (co-dimension) of each mesh point
7152 . "celltype"    - Holds the topological type of each cell
7153 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7154 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7155 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7156 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7157 
7158   Level: intermediate
7159 
7160 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7161 @*/
7162 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7163 {
7164   DMLabelLink next = dm->labels;
7165   PetscBool   hasLabel;
7166   const char *lname;
7167 
7168   PetscFunctionBegin;
7169   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7170   PetscAssertPointer(name, 2);
7171   PetscAssertPointer(label, 3);
7172   *label = NULL;
7173   while (next) {
7174     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7175     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7176     if (hasLabel) {
7177       *label = next->label;
7178       break;
7179     }
7180     next = next->next;
7181   }
7182   PetscFunctionReturn(PETSC_SUCCESS);
7183 }
7184 
7185 /*@
7186   DMGetLabelByNum - Return the nth label on a `DM`
7187 
7188   Not Collective
7189 
7190   Input Parameters:
7191 + dm - The `DM` object
7192 - n  - the label number
7193 
7194   Output Parameter:
7195 . label - the label
7196 
7197   Level: intermediate
7198 
7199 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7200 @*/
7201 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7202 {
7203   DMLabelLink next = dm->labels;
7204   PetscInt    l    = 0;
7205 
7206   PetscFunctionBegin;
7207   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7208   PetscAssertPointer(label, 3);
7209   while (next) {
7210     if (l == n) {
7211       *label = next->label;
7212       PetscFunctionReturn(PETSC_SUCCESS);
7213     }
7214     ++l;
7215     next = next->next;
7216   }
7217   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7218 }
7219 
7220 /*@
7221   DMAddLabel - Add the label to this `DM`
7222 
7223   Not Collective
7224 
7225   Input Parameters:
7226 + dm    - The `DM` object
7227 - label - The `DMLabel`
7228 
7229   Level: developer
7230 
7231 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7232 @*/
7233 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7234 {
7235   DMLabelLink l, *p, tmpLabel;
7236   PetscBool   hasLabel;
7237   const char *lname;
7238   PetscBool   flg;
7239 
7240   PetscFunctionBegin;
7241   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7242   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7243   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7244   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7245   PetscCall(PetscCalloc1(1, &tmpLabel));
7246   tmpLabel->label  = label;
7247   tmpLabel->output = PETSC_TRUE;
7248   for (p = &dm->labels; (l = *p); p = &l->next) { }
7249   *p = tmpLabel;
7250   PetscCall(PetscObjectReference((PetscObject)label));
7251   PetscCall(PetscStrcmp(lname, "depth", &flg));
7252   if (flg) dm->depthLabel = label;
7253   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7254   if (flg) dm->celltypeLabel = label;
7255   PetscFunctionReturn(PETSC_SUCCESS);
7256 }
7257 
7258 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7259 /*@
7260   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7261 
7262   Not Collective
7263 
7264   Input Parameters:
7265 + dm    - The `DM` object
7266 - label - The `DMLabel`, having the same name, to substitute
7267 
7268   Default labels in a `DMPLEX`:
7269 + "depth"       - Holds the depth (co-dimension) of each mesh point
7270 . "celltype"    - Holds the topological type of each cell
7271 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7272 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7273 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7274 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7275 
7276   Level: intermediate
7277 
7278 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7279 @*/
7280 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7281 {
7282   DMLabelLink next = dm->labels;
7283   PetscBool   hasLabel, flg;
7284   const char *name, *lname;
7285 
7286   PetscFunctionBegin;
7287   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7288   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7289   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7290   while (next) {
7291     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7292     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7293     if (hasLabel) {
7294       PetscCall(PetscObjectReference((PetscObject)label));
7295       PetscCall(PetscStrcmp(lname, "depth", &flg));
7296       if (flg) dm->depthLabel = label;
7297       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7298       if (flg) dm->celltypeLabel = label;
7299       PetscCall(DMLabelDestroy(&next->label));
7300       next->label = label;
7301       break;
7302     }
7303     next = next->next;
7304   }
7305   PetscFunctionReturn(PETSC_SUCCESS);
7306 }
7307 
7308 /*@
7309   DMRemoveLabel - Remove the label given by name from this `DM`
7310 
7311   Not Collective
7312 
7313   Input Parameters:
7314 + dm   - The `DM` object
7315 - name - The label name
7316 
7317   Output Parameter:
7318 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7319           caller is responsible for calling `DMLabelDestroy()`.
7320 
7321   Level: developer
7322 
7323 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7324 @*/
7325 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7326 {
7327   DMLabelLink link, *pnext;
7328   PetscBool   hasLabel;
7329   const char *lname;
7330 
7331   PetscFunctionBegin;
7332   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7333   PetscAssertPointer(name, 2);
7334   if (label) {
7335     PetscAssertPointer(label, 3);
7336     *label = NULL;
7337   }
7338   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7339     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7340     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7341     if (hasLabel) {
7342       *pnext = link->next; /* Remove from list */
7343       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7344       if (hasLabel) dm->depthLabel = NULL;
7345       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7346       if (hasLabel) dm->celltypeLabel = NULL;
7347       if (label) *label = link->label;
7348       else PetscCall(DMLabelDestroy(&link->label));
7349       PetscCall(PetscFree(link));
7350       break;
7351     }
7352   }
7353   PetscFunctionReturn(PETSC_SUCCESS);
7354 }
7355 
7356 /*@
7357   DMRemoveLabelBySelf - Remove the label from this `DM`
7358 
7359   Not Collective
7360 
7361   Input Parameters:
7362 + dm           - The `DM` object
7363 . label        - The `DMLabel` to be removed from the `DM`
7364 - failNotFound - Should it fail if the label is not found in the `DM`?
7365 
7366   Level: developer
7367 
7368   Note:
7369   Only exactly the same instance is removed if found, name match is ignored.
7370   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7371   *label nullified.
7372 
7373 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7374 @*/
7375 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7376 {
7377   DMLabelLink link, *pnext;
7378   PetscBool   hasLabel = PETSC_FALSE;
7379 
7380   PetscFunctionBegin;
7381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7382   PetscAssertPointer(label, 2);
7383   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7384   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7385   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7386   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7387     if (*label == link->label) {
7388       hasLabel = PETSC_TRUE;
7389       *pnext   = link->next; /* Remove from list */
7390       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7391       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7392       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7393       PetscCall(DMLabelDestroy(&link->label));
7394       PetscCall(PetscFree(link));
7395       break;
7396     }
7397   }
7398   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7399   PetscFunctionReturn(PETSC_SUCCESS);
7400 }
7401 
7402 /*@
7403   DMGetLabelOutput - Get the output flag for a given label
7404 
7405   Not Collective
7406 
7407   Input Parameters:
7408 + dm   - The `DM` object
7409 - name - The label name
7410 
7411   Output Parameter:
7412 . output - The flag for output
7413 
7414   Level: developer
7415 
7416 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7417 @*/
7418 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7419 {
7420   DMLabelLink next = dm->labels;
7421   const char *lname;
7422 
7423   PetscFunctionBegin;
7424   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7425   PetscAssertPointer(name, 2);
7426   PetscAssertPointer(output, 3);
7427   while (next) {
7428     PetscBool flg;
7429 
7430     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7431     PetscCall(PetscStrcmp(name, lname, &flg));
7432     if (flg) {
7433       *output = next->output;
7434       PetscFunctionReturn(PETSC_SUCCESS);
7435     }
7436     next = next->next;
7437   }
7438   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7439 }
7440 
7441 /*@
7442   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7443 
7444   Not Collective
7445 
7446   Input Parameters:
7447 + dm     - The `DM` object
7448 . name   - The label name
7449 - output - `PETSC_TRUE` to save the label to the viewer
7450 
7451   Level: developer
7452 
7453 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7454 @*/
7455 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7456 {
7457   DMLabelLink next = dm->labels;
7458   const char *lname;
7459 
7460   PetscFunctionBegin;
7461   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7462   PetscAssertPointer(name, 2);
7463   while (next) {
7464     PetscBool flg;
7465 
7466     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7467     PetscCall(PetscStrcmp(name, lname, &flg));
7468     if (flg) {
7469       next->output = output;
7470       PetscFunctionReturn(PETSC_SUCCESS);
7471     }
7472     next = next->next;
7473   }
7474   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7475 }
7476 
7477 /*@
7478   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7479 
7480   Collective
7481 
7482   Input Parameters:
7483 + dmA   - The `DM` object with initial labels
7484 . dmB   - The `DM` object to which labels are copied
7485 . mode  - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7486 . all   - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7487 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7488 
7489   Level: intermediate
7490 
7491   Note:
7492   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7493 
7494 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7495 @*/
7496 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7497 {
7498   DMLabel     label, labelNew, labelOld;
7499   const char *name;
7500   PetscBool   flg;
7501   DMLabelLink link;
7502 
7503   PetscFunctionBegin;
7504   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7505   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7506   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7507   PetscValidLogicalCollectiveBool(dmA, all, 4);
7508   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7509   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7510   for (link = dmA->labels; link; link = link->next) {
7511     label = link->label;
7512     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7513     if (!all) {
7514       PetscCall(PetscStrcmp(name, "depth", &flg));
7515       if (flg) continue;
7516       PetscCall(PetscStrcmp(name, "dim", &flg));
7517       if (flg) continue;
7518       PetscCall(PetscStrcmp(name, "celltype", &flg));
7519       if (flg) continue;
7520     }
7521     PetscCall(DMGetLabel(dmB, name, &labelOld));
7522     if (labelOld) {
7523       switch (emode) {
7524       case DM_COPY_LABELS_KEEP:
7525         continue;
7526       case DM_COPY_LABELS_REPLACE:
7527         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7528         break;
7529       case DM_COPY_LABELS_FAIL:
7530         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7531       default:
7532         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7533       }
7534     }
7535     if (mode == PETSC_COPY_VALUES) {
7536       PetscCall(DMLabelDuplicate(label, &labelNew));
7537     } else {
7538       labelNew = label;
7539     }
7540     PetscCall(DMAddLabel(dmB, labelNew));
7541     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7542   }
7543   PetscFunctionReturn(PETSC_SUCCESS);
7544 }
7545 
7546 /*@C
7547   DMCompareLabels - Compare labels between two `DM` objects
7548 
7549   Collective; No Fortran Support
7550 
7551   Input Parameters:
7552 + dm0 - First `DM` object
7553 - dm1 - Second `DM` object
7554 
7555   Output Parameters:
7556 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7557 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7558 
7559   Level: intermediate
7560 
7561   Notes:
7562   The output flag equal will be the same on all processes.
7563 
7564   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7565 
7566   Make sure to pass equal is `NULL` on all processes or none of them.
7567 
7568   The output message is set independently on each rank.
7569 
7570   message must be freed with `PetscFree()`
7571 
7572   If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner.
7573 
7574   Make sure to pass message as `NULL` on all processes or no processes.
7575 
7576   Labels are matched by name. If the number of labels and their names are equal,
7577   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7578 
7579   Developer Note:
7580   Can automatically generate the Fortran stub because `message` must be freed with `PetscFree()`
7581 
7582 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7583 @*/
7584 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7585 {
7586   PetscInt    n, i;
7587   char        msg[PETSC_MAX_PATH_LEN] = "";
7588   PetscBool   eq;
7589   MPI_Comm    comm;
7590   PetscMPIInt rank;
7591 
7592   PetscFunctionBegin;
7593   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7594   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7595   PetscCheckSameComm(dm0, 1, dm1, 2);
7596   if (equal) PetscAssertPointer(equal, 3);
7597   if (message) PetscAssertPointer(message, 4);
7598   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7599   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7600   {
7601     PetscInt n1;
7602 
7603     PetscCall(DMGetNumLabels(dm0, &n));
7604     PetscCall(DMGetNumLabels(dm1, &n1));
7605     eq = (PetscBool)(n == n1);
7606     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7607     PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7608     if (!eq) goto finish;
7609   }
7610   for (i = 0; i < n; i++) {
7611     DMLabel     l0, l1;
7612     const char *name;
7613     char       *msgInner;
7614 
7615     /* Ignore label order */
7616     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7617     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7618     PetscCall(DMGetLabel(dm1, name, &l1));
7619     if (!l1) {
7620       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7621       eq = PETSC_FALSE;
7622       break;
7623     }
7624     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7625     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7626     PetscCall(PetscFree(msgInner));
7627     if (!eq) break;
7628   }
7629   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7630 finish:
7631   /* If message output arg not set, print to stderr */
7632   if (message) {
7633     *message = NULL;
7634     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7635   } else {
7636     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7637     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7638   }
7639   /* If same output arg not ser and labels are not equal, throw error */
7640   if (equal) *equal = eq;
7641   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7642   PetscFunctionReturn(PETSC_SUCCESS);
7643 }
7644 
7645 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7646 {
7647   PetscFunctionBegin;
7648   PetscAssertPointer(label, 2);
7649   if (!*label) {
7650     PetscCall(DMCreateLabel(dm, name));
7651     PetscCall(DMGetLabel(dm, name, label));
7652   }
7653   PetscCall(DMLabelSetValue(*label, point, value));
7654   PetscFunctionReturn(PETSC_SUCCESS);
7655 }
7656 
7657 /*
7658   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7659   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7660   (label, id) pair in the DM.
7661 
7662   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7663   each label.
7664 */
7665 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7666 {
7667   DMUniversalLabel ul;
7668   PetscBool       *active;
7669   PetscInt         pStart, pEnd, p, Nl, l, m;
7670 
7671   PetscFunctionBegin;
7672   PetscCall(PetscMalloc1(1, &ul));
7673   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7674   PetscCall(DMGetNumLabels(dm, &Nl));
7675   PetscCall(PetscCalloc1(Nl, &active));
7676   ul->Nl = 0;
7677   for (l = 0; l < Nl; ++l) {
7678     PetscBool   isdepth, iscelltype;
7679     const char *name;
7680 
7681     PetscCall(DMGetLabelName(dm, l, &name));
7682     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7683     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7684     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7685     if (active[l]) ++ul->Nl;
7686   }
7687   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7688   ul->Nv = 0;
7689   for (l = 0, m = 0; l < Nl; ++l) {
7690     DMLabel     label;
7691     PetscInt    nv;
7692     const char *name;
7693 
7694     if (!active[l]) continue;
7695     PetscCall(DMGetLabelName(dm, l, &name));
7696     PetscCall(DMGetLabelByNum(dm, l, &label));
7697     PetscCall(DMLabelGetNumValues(label, &nv));
7698     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7699     ul->indices[m] = l;
7700     ul->Nv += nv;
7701     ul->offsets[m + 1] = nv;
7702     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7703     ++m;
7704   }
7705   for (l = 1; l <= ul->Nl; ++l) {
7706     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7707     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7708   }
7709   for (l = 0; l < ul->Nl; ++l) {
7710     PetscInt b;
7711 
7712     ul->masks[l] = 0;
7713     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7714   }
7715   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7716   for (l = 0, m = 0; l < Nl; ++l) {
7717     DMLabel         label;
7718     IS              valueIS;
7719     const PetscInt *varr;
7720     PetscInt        nv, v;
7721 
7722     if (!active[l]) continue;
7723     PetscCall(DMGetLabelByNum(dm, l, &label));
7724     PetscCall(DMLabelGetNumValues(label, &nv));
7725     PetscCall(DMLabelGetValueIS(label, &valueIS));
7726     PetscCall(ISGetIndices(valueIS, &varr));
7727     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7728     PetscCall(ISRestoreIndices(valueIS, &varr));
7729     PetscCall(ISDestroy(&valueIS));
7730     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7731     ++m;
7732   }
7733   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7734   for (p = pStart; p < pEnd; ++p) {
7735     PetscInt  uval   = 0;
7736     PetscBool marked = PETSC_FALSE;
7737 
7738     for (l = 0, m = 0; l < Nl; ++l) {
7739       DMLabel  label;
7740       PetscInt val, defval, loc, nv;
7741 
7742       if (!active[l]) continue;
7743       PetscCall(DMGetLabelByNum(dm, l, &label));
7744       PetscCall(DMLabelGetValue(label, p, &val));
7745       PetscCall(DMLabelGetDefaultValue(label, &defval));
7746       if (val == defval) {
7747         ++m;
7748         continue;
7749       }
7750       nv     = ul->offsets[m + 1] - ul->offsets[m];
7751       marked = PETSC_TRUE;
7752       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7753       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7754       uval += (loc + 1) << ul->bits[m];
7755       ++m;
7756     }
7757     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7758   }
7759   PetscCall(PetscFree(active));
7760   *universal = ul;
7761   PetscFunctionReturn(PETSC_SUCCESS);
7762 }
7763 
7764 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7765 {
7766   PetscInt l;
7767 
7768   PetscFunctionBegin;
7769   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7770   PetscCall(DMLabelDestroy(&(*universal)->label));
7771   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7772   PetscCall(PetscFree((*universal)->values));
7773   PetscCall(PetscFree(*universal));
7774   *universal = NULL;
7775   PetscFunctionReturn(PETSC_SUCCESS);
7776 }
7777 
7778 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7779 {
7780   PetscFunctionBegin;
7781   PetscAssertPointer(ulabel, 2);
7782   *ulabel = ul->label;
7783   PetscFunctionReturn(PETSC_SUCCESS);
7784 }
7785 
7786 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7787 {
7788   PetscInt Nl = ul->Nl, l;
7789 
7790   PetscFunctionBegin;
7791   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7792   for (l = 0; l < Nl; ++l) {
7793     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7794     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7795   }
7796   if (preserveOrder) {
7797     for (l = 0; l < ul->Nl; ++l) {
7798       const char *name;
7799       PetscBool   match;
7800 
7801       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7802       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7803       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]);
7804     }
7805   }
7806   PetscFunctionReturn(PETSC_SUCCESS);
7807 }
7808 
7809 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7810 {
7811   PetscInt l;
7812 
7813   PetscFunctionBegin;
7814   for (l = 0; l < ul->Nl; ++l) {
7815     DMLabel  label;
7816     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7817 
7818     if (lval) {
7819       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7820       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7821       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7822     }
7823   }
7824   PetscFunctionReturn(PETSC_SUCCESS);
7825 }
7826 
7827 /*@
7828   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7829 
7830   Not Collective
7831 
7832   Input Parameter:
7833 . dm - The `DM` object
7834 
7835   Output Parameter:
7836 . cdm - The coarse `DM`
7837 
7838   Level: intermediate
7839 
7840 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7841 @*/
7842 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7843 {
7844   PetscFunctionBegin;
7845   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7846   PetscAssertPointer(cdm, 2);
7847   *cdm = dm->coarseMesh;
7848   PetscFunctionReturn(PETSC_SUCCESS);
7849 }
7850 
7851 /*@
7852   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7853 
7854   Input Parameters:
7855 + dm  - The `DM` object
7856 - cdm - The coarse `DM`
7857 
7858   Level: intermediate
7859 
7860   Note:
7861   Normally this is set automatically by `DMRefine()`
7862 
7863 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7864 @*/
7865 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7866 {
7867   PetscFunctionBegin;
7868   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7869   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7870   if (dm == cdm) cdm = NULL;
7871   PetscCall(PetscObjectReference((PetscObject)cdm));
7872   PetscCall(DMDestroy(&dm->coarseMesh));
7873   dm->coarseMesh = cdm;
7874   PetscFunctionReturn(PETSC_SUCCESS);
7875 }
7876 
7877 /*@
7878   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7879 
7880   Input Parameter:
7881 . dm - The `DM` object
7882 
7883   Output Parameter:
7884 . fdm - The fine `DM`
7885 
7886   Level: intermediate
7887 
7888 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7889 @*/
7890 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7891 {
7892   PetscFunctionBegin;
7893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7894   PetscAssertPointer(fdm, 2);
7895   *fdm = dm->fineMesh;
7896   PetscFunctionReturn(PETSC_SUCCESS);
7897 }
7898 
7899 /*@
7900   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7901 
7902   Input Parameters:
7903 + dm  - The `DM` object
7904 - fdm - The fine `DM`
7905 
7906   Level: developer
7907 
7908   Note:
7909   Normally this is set automatically by `DMCoarsen()`
7910 
7911 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7912 @*/
7913 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7914 {
7915   PetscFunctionBegin;
7916   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7917   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7918   if (dm == fdm) fdm = NULL;
7919   PetscCall(PetscObjectReference((PetscObject)fdm));
7920   PetscCall(DMDestroy(&dm->fineMesh));
7921   dm->fineMesh = fdm;
7922   PetscFunctionReturn(PETSC_SUCCESS);
7923 }
7924 
7925 /*@C
7926   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7927 
7928   Collective
7929 
7930   Input Parameters:
7931 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7932 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7933 . name     - The BC name
7934 . label    - The label defining constrained points
7935 . Nv       - The number of `DMLabel` values for constrained points
7936 . values   - An array of values for constrained points
7937 . field    - The field to constrain
7938 . Nc       - The number of constrained field components (0 will constrain all fields)
7939 . comps    - An array of constrained component numbers
7940 . bcFunc   - A pointwise function giving boundary values
7941 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7942 - ctx      - An optional user context for bcFunc
7943 
7944   Output Parameter:
7945 . bd - (Optional) Boundary number
7946 
7947   Options Database Keys:
7948 + -bc_<boundary name> <num>      - Overrides the boundary ids
7949 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7950 
7951   Level: intermediate
7952 
7953   Notes:
7954   Both bcFunc and bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
7955 .vb
7956  void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
7957 .ve
7958 
7959   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
7960 
7961 .vb
7962   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7963               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7964               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7965               PetscReal time, const PetscReal x[], PetscScalar bcval[])
7966 .ve
7967 + dim - the spatial dimension
7968 . Nf - the number of fields
7969 . uOff - the offset into u[] and u_t[] for each field
7970 . uOff_x - the offset into u_x[] for each field
7971 . u - each field evaluated at the current point
7972 . u_t - the time derivative of each field evaluated at the current point
7973 . u_x - the gradient of each field evaluated at the current point
7974 . aOff - the offset into a[] and a_t[] for each auxiliary field
7975 . aOff_x - the offset into a_x[] for each auxiliary field
7976 . a - each auxiliary field evaluated at the current point
7977 . a_t - the time derivative of each auxiliary field evaluated at the current point
7978 . a_x - the gradient of auxiliary each field evaluated at the current point
7979 . t - current time
7980 . x - coordinates of the current point
7981 . numConstants - number of constant parameters
7982 . constants - constant parameters
7983 - bcval - output values at the current point
7984 
7985 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
7986 @*/
7987 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)
7988 {
7989   PetscDS ds;
7990 
7991   PetscFunctionBegin;
7992   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7993   PetscValidLogicalCollectiveEnum(dm, type, 2);
7994   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
7995   PetscValidLogicalCollectiveInt(dm, Nv, 5);
7996   PetscValidLogicalCollectiveInt(dm, field, 7);
7997   PetscValidLogicalCollectiveInt(dm, Nc, 8);
7998   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
7999   PetscCall(DMGetDS(dm, &ds));
8000   /* Complete label */
8001   if (label) {
8002     PetscObject  obj;
8003     PetscClassId id;
8004 
8005     PetscCall(DMGetField(dm, field, NULL, &obj));
8006     PetscCall(PetscObjectGetClassId(obj, &id));
8007     if (id == PETSCFE_CLASSID) {
8008       DM plex;
8009 
8010       PetscCall(DMConvert(dm, DMPLEX, &plex));
8011       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8012       PetscCall(DMDestroy(&plex));
8013     }
8014   }
8015   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8016   PetscFunctionReturn(PETSC_SUCCESS);
8017 }
8018 
8019 /* TODO Remove this since now the structures are the same */
8020 static PetscErrorCode DMPopulateBoundary(DM dm)
8021 {
8022   PetscDS     ds;
8023   DMBoundary *lastnext;
8024   DSBoundary  dsbound;
8025 
8026   PetscFunctionBegin;
8027   PetscCall(DMGetDS(dm, &ds));
8028   dsbound = ds->boundary;
8029   if (dm->boundary) {
8030     DMBoundary next = dm->boundary;
8031 
8032     /* quick check to see if the PetscDS has changed */
8033     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
8034     /* the PetscDS has changed: tear down and rebuild */
8035     while (next) {
8036       DMBoundary b = next;
8037 
8038       next = b->next;
8039       PetscCall(PetscFree(b));
8040     }
8041     dm->boundary = NULL;
8042   }
8043 
8044   lastnext = &dm->boundary;
8045   while (dsbound) {
8046     DMBoundary dmbound;
8047 
8048     PetscCall(PetscNew(&dmbound));
8049     dmbound->dsboundary = dsbound;
8050     dmbound->label      = dsbound->label;
8051     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8052     *lastnext = dmbound;
8053     lastnext  = &dmbound->next;
8054     dsbound   = dsbound->next;
8055   }
8056   PetscFunctionReturn(PETSC_SUCCESS);
8057 }
8058 
8059 /* TODO: missing manual page */
8060 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8061 {
8062   DMBoundary b;
8063 
8064   PetscFunctionBegin;
8065   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8066   PetscAssertPointer(isBd, 3);
8067   *isBd = PETSC_FALSE;
8068   PetscCall(DMPopulateBoundary(dm));
8069   b = dm->boundary;
8070   while (b && !*isBd) {
8071     DMLabel    label = b->label;
8072     DSBoundary dsb   = b->dsboundary;
8073     PetscInt   i;
8074 
8075     if (label) {
8076       for (i = 0; i < dsb->Nv && !*isBd; ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8077     }
8078     b = b->next;
8079   }
8080   PetscFunctionReturn(PETSC_SUCCESS);
8081 }
8082 
8083 /*@C
8084   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
8085 
8086   Collective
8087 
8088   Input Parameters:
8089 + dm    - The `DM`
8090 . time  - The time
8091 . funcs - The coordinate functions to evaluate, one per field
8092 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8093 - mode  - The insertion mode for values
8094 
8095   Output Parameter:
8096 . X - vector
8097 
8098   Calling sequence of `funcs`:
8099 + dim  - The spatial dimension
8100 . time - The time at which to sample
8101 . x    - The coordinates
8102 . Nc   - The number of components
8103 . u    - The output field values
8104 - ctx  - optional user-defined function context
8105 
8106   Level: developer
8107 
8108   Developer Notes:
8109   This API is specific to only particular usage of `DM`
8110 
8111   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8112 
8113 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8114 @*/
8115 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)
8116 {
8117   Vec localX;
8118 
8119   PetscFunctionBegin;
8120   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8121   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
8122   PetscCall(DMGetLocalVector(dm, &localX));
8123   PetscCall(VecSet(localX, 0.));
8124   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8125   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8126   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8127   PetscCall(DMRestoreLocalVector(dm, &localX));
8128   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
8129   PetscFunctionReturn(PETSC_SUCCESS);
8130 }
8131 
8132 /*@C
8133   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
8134 
8135   Not Collective
8136 
8137   Input Parameters:
8138 + dm    - The `DM`
8139 . time  - The time
8140 . funcs - The coordinate functions to evaluate, one per field
8141 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8142 - mode  - The insertion mode for values
8143 
8144   Output Parameter:
8145 . localX - vector
8146 
8147   Calling sequence of `funcs`:
8148 + dim  - The spatial dimension
8149 . time - The current timestep
8150 . x    - The coordinates
8151 . Nc   - The number of components
8152 . u    - The output field values
8153 - ctx  - optional user-defined function context
8154 
8155   Level: developer
8156 
8157   Developer Notes:
8158   This API is specific to only particular usage of `DM`
8159 
8160   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8161 
8162 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8163 @*/
8164 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)
8165 {
8166   PetscFunctionBegin;
8167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8168   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8169   PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX);
8170   PetscFunctionReturn(PETSC_SUCCESS);
8171 }
8172 
8173 /*@C
8174   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.
8175 
8176   Collective
8177 
8178   Input Parameters:
8179 + dm     - The `DM`
8180 . time   - The time
8181 . numIds - The number of ids
8182 . ids    - The ids
8183 . Nc     - The number of components
8184 . comps  - The components
8185 . label  - The `DMLabel` selecting the portion of the mesh for projection
8186 . funcs  - The coordinate functions to evaluate, one per field
8187 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8188 - mode   - The insertion mode for values
8189 
8190   Output Parameter:
8191 . X - vector
8192 
8193   Calling sequence of `funcs`:
8194 + dim  - The spatial dimension
8195 . time - The current timestep
8196 . x    - The coordinates
8197 . Nc   - The number of components
8198 . u    - The output field values
8199 - ctx  - optional user-defined function context
8200 
8201   Level: developer
8202 
8203   Developer Notes:
8204   This API is specific to only particular usage of `DM`
8205 
8206   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8207 
8208 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8209 @*/
8210 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)
8211 {
8212   Vec localX;
8213 
8214   PetscFunctionBegin;
8215   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8216   PetscCall(DMGetLocalVector(dm, &localX));
8217   PetscCall(VecSet(localX, 0.));
8218   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8219   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8220   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8221   PetscCall(DMRestoreLocalVector(dm, &localX));
8222   PetscFunctionReturn(PETSC_SUCCESS);
8223 }
8224 
8225 /*@C
8226   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.
8227 
8228   Not Collective
8229 
8230   Input Parameters:
8231 + dm     - The `DM`
8232 . time   - The time
8233 . label  - The `DMLabel` selecting the portion of the mesh for projection
8234 . numIds - The number of ids
8235 . ids    - The ids
8236 . Nc     - The number of components
8237 . comps  - The components
8238 . funcs  - The coordinate functions to evaluate, one per field
8239 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8240 - mode   - The insertion mode for values
8241 
8242   Output Parameter:
8243 . localX - vector
8244 
8245   Calling sequence of `funcs`:
8246 + dim  - The spatial dimension
8247 . time - The current time
8248 . x    - The coordinates
8249 . Nc   - The number of components
8250 . u    - The output field values
8251 - ctx  - optional user-defined function context
8252 
8253   Level: developer
8254 
8255   Developer Notes:
8256   This API is specific to only particular usage of `DM`
8257 
8258   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8259 
8260 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8261 @*/
8262 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)
8263 {
8264   PetscFunctionBegin;
8265   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8266   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8267   PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);
8268   PetscFunctionReturn(PETSC_SUCCESS);
8269 }
8270 
8271 /*@C
8272   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.
8273 
8274   Not Collective
8275 
8276   Input Parameters:
8277 + dm     - The `DM`
8278 . time   - The time
8279 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8280 . funcs  - The functions to evaluate, one per field
8281 - mode   - The insertion mode for values
8282 
8283   Output Parameter:
8284 . localX - The output vector
8285 
8286   Calling sequence of `funcs`:
8287 + dim          - The spatial dimension
8288 . Nf           - The number of input fields
8289 . NfAux        - The number of input auxiliary fields
8290 . uOff         - The offset of each field in u[]
8291 . uOff_x       - The offset of each field in u_x[]
8292 . u            - The field values at this point in space
8293 . u_t          - The field time derivative at this point in space (or NULL)
8294 . u_x          - The field derivatives at this point in space
8295 . aOff         - The offset of each auxiliary field in u[]
8296 . aOff_x       - The offset of each auxiliary field in u_x[]
8297 . a            - The auxiliary field values at this point in space
8298 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8299 . a_x          - The auxiliary field derivatives at this point in space
8300 . t            - The current time
8301 . x            - The coordinates of this point
8302 . numConstants - The number of constants
8303 . constants    - The value of each constant
8304 - f            - The value of the function at this point in space
8305 
8306   Level: intermediate
8307 
8308   Note:
8309   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.
8310   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
8311   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8312   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8313 
8314   Developer Notes:
8315   This API is specific to only particular usage of `DM`
8316 
8317   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8318 
8319 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8320 `DMProjectFunction()`, `DMComputeL2Diff()`
8321 @*/
8322 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)
8323 {
8324   PetscFunctionBegin;
8325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8326   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8327   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8328   PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX);
8329   PetscFunctionReturn(PETSC_SUCCESS);
8330 }
8331 
8332 /*@C
8333   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.
8334 
8335   Not Collective
8336 
8337   Input Parameters:
8338 + dm     - The `DM`
8339 . time   - The time
8340 . label  - The `DMLabel` marking the portion of the domain to output
8341 . numIds - The number of label ids to use
8342 . ids    - The label ids to use for marking
8343 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8344 . comps  - The components to set in the output, or `NULL` for all components
8345 . localU - The input field vector
8346 . funcs  - The functions to evaluate, one per field
8347 - mode   - The insertion mode for values
8348 
8349   Output Parameter:
8350 . localX - The output vector
8351 
8352   Calling sequence of `funcs`:
8353 + dim          - The spatial dimension
8354 . Nf           - The number of input fields
8355 . NfAux        - The number of input auxiliary fields
8356 . uOff         - The offset of each field in u[]
8357 . uOff_x       - The offset of each field in u_x[]
8358 . u            - The field values at this point in space
8359 . u_t          - The field time derivative at this point in space (or NULL)
8360 . u_x          - The field derivatives at this point in space
8361 . aOff         - The offset of each auxiliary field in u[]
8362 . aOff_x       - The offset of each auxiliary field in u_x[]
8363 . a            - The auxiliary field values at this point in space
8364 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8365 . a_x          - The auxiliary field derivatives at this point in space
8366 . t            - The current time
8367 . x            - The coordinates of this point
8368 . numConstants - The number of constants
8369 . constants    - The value of each constant
8370 - f            - The value of the function at this point in space
8371 
8372   Level: intermediate
8373 
8374   Note:
8375   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.
8376   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
8377   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8378   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8379 
8380   Developer Notes:
8381   This API is specific to only particular usage of `DM`
8382 
8383   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8384 
8385 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8386 @*/
8387 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)
8388 {
8389   PetscFunctionBegin;
8390   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8391   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8392   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8393   PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8394   PetscFunctionReturn(PETSC_SUCCESS);
8395 }
8396 
8397 /*@C
8398   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.
8399 
8400   Not Collective
8401 
8402   Input Parameters:
8403 + dm     - The `DM`
8404 . time   - The time
8405 . label  - The `DMLabel` marking the portion of the domain to output
8406 . numIds - The number of label ids to use
8407 . ids    - The label ids to use for marking
8408 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8409 . comps  - The components to set in the output, or `NULL` for all components
8410 . U      - The input field vector
8411 . funcs  - The functions to evaluate, one per field
8412 - mode   - The insertion mode for values
8413 
8414   Output Parameter:
8415 . X - The output vector
8416 
8417   Calling sequence of `funcs`:
8418 + dim          - The spatial dimension
8419 . Nf           - The number of input fields
8420 . NfAux        - The number of input auxiliary fields
8421 . uOff         - The offset of each field in u[]
8422 . uOff_x       - The offset of each field in u_x[]
8423 . u            - The field values at this point in space
8424 . u_t          - The field time derivative at this point in space (or NULL)
8425 . u_x          - The field derivatives at this point in space
8426 . aOff         - The offset of each auxiliary field in u[]
8427 . aOff_x       - The offset of each auxiliary field in u_x[]
8428 . a            - The auxiliary field values at this point in space
8429 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8430 . a_x          - The auxiliary field derivatives at this point in space
8431 . t            - The current time
8432 . x            - The coordinates of this point
8433 . numConstants - The number of constants
8434 . constants    - The value of each constant
8435 - f            - The value of the function at this point in space
8436 
8437   Level: intermediate
8438 
8439   Note:
8440   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.
8441   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
8442   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8443   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8444 
8445   Developer Notes:
8446   This API is specific to only particular usage of `DM`
8447 
8448   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8449 
8450 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8451 @*/
8452 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)
8453 {
8454   DM  dmIn;
8455   Vec localU, localX;
8456 
8457   PetscFunctionBegin;
8458   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8459   PetscCall(VecGetDM(U, &dmIn));
8460   PetscCall(DMGetLocalVector(dmIn, &localU));
8461   PetscCall(DMGetLocalVector(dm, &localX));
8462   PetscCall(VecSet(localX, 0.));
8463   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8464   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8465   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8466   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8467   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8468   PetscCall(DMRestoreLocalVector(dm, &localX));
8469   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8470   PetscFunctionReturn(PETSC_SUCCESS);
8471 }
8472 
8473 /*@C
8474   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.
8475 
8476   Not Collective
8477 
8478   Input Parameters:
8479 + dm     - The `DM`
8480 . time   - The time
8481 . label  - The `DMLabel` marking the portion of the domain boundary to output
8482 . numIds - The number of label ids to use
8483 . ids    - The label ids to use for marking
8484 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8485 . comps  - The components to set in the output, or `NULL` for all components
8486 . localU - The input field vector
8487 . funcs  - The functions to evaluate, one per field
8488 - mode   - The insertion mode for values
8489 
8490   Output Parameter:
8491 . localX - The output vector
8492 
8493   Calling sequence of `funcs`:
8494 + dim          - The spatial dimension
8495 . Nf           - The number of input fields
8496 . NfAux        - The number of input auxiliary fields
8497 . uOff         - The offset of each field in u[]
8498 . uOff_x       - The offset of each field in u_x[]
8499 . u            - The field values at this point in space
8500 . u_t          - The field time derivative at this point in space (or NULL)
8501 . u_x          - The field derivatives at this point in space
8502 . aOff         - The offset of each auxiliary field in u[]
8503 . aOff_x       - The offset of each auxiliary field in u_x[]
8504 . a            - The auxiliary field values at this point in space
8505 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8506 . a_x          - The auxiliary field derivatives at this point in space
8507 . t            - The current time
8508 . x            - The coordinates of this point
8509 . n            - The face normal
8510 . numConstants - The number of constants
8511 . constants    - The value of each constant
8512 - f            - The value of the function at this point in space
8513 
8514   Level: intermediate
8515 
8516   Note:
8517   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.
8518   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
8519   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8520   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8521 
8522   Developer Notes:
8523   This API is specific to only particular usage of `DM`
8524 
8525   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8526 
8527 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8528 @*/
8529 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)
8530 {
8531   PetscFunctionBegin;
8532   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8533   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8534   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8535   PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);
8536   PetscFunctionReturn(PETSC_SUCCESS);
8537 }
8538 
8539 /*@C
8540   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8541 
8542   Collective
8543 
8544   Input Parameters:
8545 + dm    - The `DM`
8546 . time  - The time
8547 . funcs - The functions to evaluate for each field component
8548 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8549 - X     - The coefficient vector u_h, a global vector
8550 
8551   Output Parameter:
8552 . diff - The diff ||u - u_h||_2
8553 
8554   Level: developer
8555 
8556   Developer Notes:
8557   This API is specific to only particular usage of `DM`
8558 
8559   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8560 
8561 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8562 @*/
8563 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8564 {
8565   PetscFunctionBegin;
8566   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8567   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8568   PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff);
8569   PetscFunctionReturn(PETSC_SUCCESS);
8570 }
8571 
8572 /*@C
8573   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8574 
8575   Collective
8576 
8577   Input Parameters:
8578 + dm    - The `DM`
8579 . time  - The time
8580 . funcs - The gradient functions to evaluate for each field component
8581 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8582 . X     - The coefficient vector u_h, a global vector
8583 - n     - The vector to project along
8584 
8585   Output Parameter:
8586 . diff - The diff ||(grad u - grad u_h) . n||_2
8587 
8588   Level: developer
8589 
8590   Developer Notes:
8591   This API is specific to only particular usage of `DM`
8592 
8593   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8594 
8595 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8596 @*/
8597 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)
8598 {
8599   PetscFunctionBegin;
8600   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8601   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8602   PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff);
8603   PetscFunctionReturn(PETSC_SUCCESS);
8604 }
8605 
8606 /*@C
8607   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8608 
8609   Collective
8610 
8611   Input Parameters:
8612 + dm    - The `DM`
8613 . time  - The time
8614 . funcs - The functions to evaluate for each field component
8615 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8616 - X     - The coefficient vector u_h, a global vector
8617 
8618   Output Parameter:
8619 . diff - The array of differences, ||u^f - u^f_h||_2
8620 
8621   Level: developer
8622 
8623   Developer Notes:
8624   This API is specific to only particular usage of `DM`
8625 
8626   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8627 
8628 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8629 @*/
8630 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8631 {
8632   PetscFunctionBegin;
8633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8634   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8635   PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff);
8636   PetscFunctionReturn(PETSC_SUCCESS);
8637 }
8638 
8639 /*@C
8640   DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8641 
8642   Not Collective
8643 
8644   Input Parameter:
8645 . dm - The `DM`
8646 
8647   Output Parameters:
8648 + nranks - the number of neighbours
8649 - ranks  - the neighbors ranks
8650 
8651   Level: beginner
8652 
8653   Note:
8654   Do not free the array, it is freed when the `DM` is destroyed.
8655 
8656 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8657 @*/
8658 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8659 {
8660   PetscFunctionBegin;
8661   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8662   PetscUseTypeMethod(dm, getneighbors, nranks, ranks);
8663   PetscFunctionReturn(PETSC_SUCCESS);
8664 }
8665 
8666 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8667 
8668 /*
8669     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8670     This must be a different function because it requires DM which is not defined in the Mat library
8671 */
8672 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8673 {
8674   PetscFunctionBegin;
8675   if (coloring->ctype == IS_COLORING_LOCAL) {
8676     Vec x1local;
8677     DM  dm;
8678     PetscCall(MatGetDM(J, &dm));
8679     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8680     PetscCall(DMGetLocalVector(dm, &x1local));
8681     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8682     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8683     x1 = x1local;
8684   }
8685   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8686   if (coloring->ctype == IS_COLORING_LOCAL) {
8687     DM dm;
8688     PetscCall(MatGetDM(J, &dm));
8689     PetscCall(DMRestoreLocalVector(dm, &x1));
8690   }
8691   PetscFunctionReturn(PETSC_SUCCESS);
8692 }
8693 
8694 /*@
8695   MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8696 
8697   Input Parameters:
8698 + coloring   - The matrix to get the `DM` from
8699 - fdcoloring - the `MatFDColoring` object
8700 
8701   Level: advanced
8702 
8703   Developer Note:
8704   This routine exists because the PETSc `Mat` library does not know about the `DM` objects
8705 
8706 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8707 @*/
8708 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8709 {
8710   PetscFunctionBegin;
8711   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8712   PetscFunctionReturn(PETSC_SUCCESS);
8713 }
8714 
8715 /*@
8716   DMGetCompatibility - determine if two `DM`s are compatible
8717 
8718   Collective
8719 
8720   Input Parameters:
8721 + dm1 - the first `DM`
8722 - dm2 - the second `DM`
8723 
8724   Output Parameters:
8725 + compatible - whether or not the two `DM`s are compatible
8726 - set        - whether or not the compatible value was actually determined and set
8727 
8728   Level: advanced
8729 
8730   Notes:
8731   Two `DM`s are deemed compatible if they represent the same parallel decomposition
8732   of the same topology. This implies that the section (field data) on one
8733   "makes sense" with respect to the topology and parallel decomposition of the other.
8734   Loosely speaking, compatible `DM`s represent the same domain and parallel
8735   decomposition, but hold different data.
8736 
8737   Typically, one would confirm compatibility if intending to simultaneously iterate
8738   over a pair of vectors obtained from different `DM`s.
8739 
8740   For example, two `DMDA` objects are compatible if they have the same local
8741   and global sizes and the same stencil width. They can have different numbers
8742   of degrees of freedom per node. Thus, one could use the node numbering from
8743   either `DM` in bounds for a loop over vectors derived from either `DM`.
8744 
8745   Consider the operation of summing data living on a 2-dof `DMDA` to data living
8746   on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8747 .vb
8748   ...
8749   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8750   if (set && compatible)  {
8751     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8752     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8753     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8754     for (j=y; j<y+n; ++j) {
8755       for (i=x; i<x+m, ++i) {
8756         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8757       }
8758     }
8759     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8760     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8761   } else {
8762     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8763   }
8764   ...
8765 .ve
8766 
8767   Checking compatibility might be expensive for a given implementation of `DM`,
8768   or might be impossible to unambiguously confirm or deny. For this reason,
8769   this function may decline to determine compatibility, and hence users should
8770   always check the "set" output parameter.
8771 
8772   A `DM` is always compatible with itself.
8773 
8774   In the current implementation, `DM`s which live on "unequal" communicators
8775   (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8776   incompatible.
8777 
8778   This function is labeled "Collective," as information about all subdomains
8779   is required on each rank. However, in `DM` implementations which store all this
8780   information locally, this function may be merely "Logically Collective".
8781 
8782   Developer Note:
8783   Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8784   iff B is compatible with A. Thus, this function checks the implementations
8785   of both dm and dmc (if they are of different types), attempting to determine
8786   compatibility. It is left to `DM` implementers to ensure that symmetry is
8787   preserved. The simplest way to do this is, when implementing type-specific
8788   logic for this function, is to check for existing logic in the implementation
8789   of other `DM` types and let *set = PETSC_FALSE if found.
8790 
8791 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8792 @*/
8793 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8794 {
8795   PetscMPIInt compareResult;
8796   DMType      type, type2;
8797   PetscBool   sameType;
8798 
8799   PetscFunctionBegin;
8800   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8801   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8802 
8803   /* Declare a DM compatible with itself */
8804   if (dm1 == dm2) {
8805     *set        = PETSC_TRUE;
8806     *compatible = PETSC_TRUE;
8807     PetscFunctionReturn(PETSC_SUCCESS);
8808   }
8809 
8810   /* Declare a DM incompatible with a DM that lives on an "unequal"
8811      communicator. Note that this does not preclude compatibility with
8812      DMs living on "congruent" or "similar" communicators, but this must be
8813      determined by the implementation-specific logic */
8814   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8815   if (compareResult == MPI_UNEQUAL) {
8816     *set        = PETSC_TRUE;
8817     *compatible = PETSC_FALSE;
8818     PetscFunctionReturn(PETSC_SUCCESS);
8819   }
8820 
8821   /* Pass to the implementation-specific routine, if one exists. */
8822   if (dm1->ops->getcompatibility) {
8823     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8824     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8825   }
8826 
8827   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8828      with an implementation of this function from dm2 */
8829   PetscCall(DMGetType(dm1, &type));
8830   PetscCall(DMGetType(dm2, &type2));
8831   PetscCall(PetscStrcmp(type, type2, &sameType));
8832   if (!sameType && dm2->ops->getcompatibility) {
8833     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8834   } else {
8835     *set = PETSC_FALSE;
8836   }
8837   PetscFunctionReturn(PETSC_SUCCESS);
8838 }
8839 
8840 /*@C
8841   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8842 
8843   Logically Collective
8844 
8845   Input Parameters:
8846 + dm             - the `DM`
8847 . f              - the monitor function
8848 . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8849 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`), see `PetscCtxDestroyFn` for the calling sequence
8850 
8851   Options Database Key:
8852 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8853                        does not cancel those set via the options database.
8854 
8855   Level: intermediate
8856 
8857   Note:
8858   Several different monitoring routines may be set by calling
8859   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8860   order in which they were set.
8861 
8862   Fortran Note:
8863   Only a single monitor function can be set for each `DM` object
8864 
8865   Developer Note:
8866   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8867 
8868 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`, `PetscCtxDestroyFn`
8869 @*/
8870 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscCtxDestroyFn *monitordestroy)
8871 {
8872   PetscInt m;
8873 
8874   PetscFunctionBegin;
8875   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8876   for (m = 0; m < dm->numbermonitors; ++m) {
8877     PetscBool identical;
8878 
8879     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void))f, mctx, monitordestroy, (PetscErrorCode (*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8880     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
8881   }
8882   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8883   dm->monitor[dm->numbermonitors]          = f;
8884   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8885   dm->monitorcontext[dm->numbermonitors++] = mctx;
8886   PetscFunctionReturn(PETSC_SUCCESS);
8887 }
8888 
8889 /*@
8890   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8891 
8892   Logically Collective
8893 
8894   Input Parameter:
8895 . dm - the DM
8896 
8897   Options Database Key:
8898 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8899   into a code by calls to `DMonitorSet()`, but does not cancel those
8900   set via the options database
8901 
8902   Level: intermediate
8903 
8904   Note:
8905   There is no way to clear one specific monitor from a `DM` object.
8906 
8907 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8908 @*/
8909 PetscErrorCode DMMonitorCancel(DM dm)
8910 {
8911   PetscInt m;
8912 
8913   PetscFunctionBegin;
8914   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8915   for (m = 0; m < dm->numbermonitors; ++m) {
8916     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8917   }
8918   dm->numbermonitors = 0;
8919   PetscFunctionReturn(PETSC_SUCCESS);
8920 }
8921 
8922 /*@C
8923   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8924 
8925   Collective
8926 
8927   Input Parameters:
8928 + dm           - `DM` object you wish to monitor
8929 . name         - the monitor type one is seeking
8930 . help         - message indicating what monitoring is done
8931 . manual       - manual page for the monitor
8932 . monitor      - the monitor function, this must use a `PetscViewerFormat` as its context
8933 - 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
8934 
8935   Output Parameter:
8936 . flg - Flag set if the monitor was created
8937 
8938   Level: developer
8939 
8940 .seealso: [](ch_dmbase), `DM`, `PetscOptionsCreateViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8941           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8942           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
8943           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8944           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8945           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8946           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8947 @*/
8948 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8949 {
8950   PetscViewer       viewer;
8951   PetscViewerFormat format;
8952 
8953   PetscFunctionBegin;
8954   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8955   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
8956   if (*flg) {
8957     PetscViewerAndFormat *vf;
8958 
8959     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
8960     PetscCall(PetscViewerDestroy(&viewer));
8961     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
8962     PetscCall(DMMonitorSet(dm, monitor, vf, (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy));
8963   }
8964   PetscFunctionReturn(PETSC_SUCCESS);
8965 }
8966 
8967 /*@
8968   DMMonitor - runs the user provided monitor routines, if they exist
8969 
8970   Collective
8971 
8972   Input Parameter:
8973 . dm - The `DM`
8974 
8975   Level: developer
8976 
8977   Developer Note:
8978   Note should indicate when during the life of the `DM` the monitor is run. It appears to be
8979   related to the discretization process seems rather specialized since some `DM` have no
8980   concept of discretization.
8981 
8982 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
8983 @*/
8984 PetscErrorCode DMMonitor(DM dm)
8985 {
8986   PetscInt m;
8987 
8988   PetscFunctionBegin;
8989   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
8990   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8991   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
8992   PetscFunctionReturn(PETSC_SUCCESS);
8993 }
8994 
8995 /*@
8996   DMComputeError - Computes the error assuming the user has provided the exact solution functions
8997 
8998   Collective
8999 
9000   Input Parameters:
9001 + dm  - The `DM`
9002 - sol - The solution vector
9003 
9004   Input/Output Parameter:
9005 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
9006            contains the error in each field
9007 
9008   Output Parameter:
9009 . errorVec - A vector to hold the cellwise error (may be `NULL`)
9010 
9011   Level: developer
9012 
9013   Note:
9014   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
9015 
9016 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9017 @*/
9018 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9019 {
9020   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9021   void    **ctxs;
9022   PetscReal time;
9023   PetscInt  Nf, f, Nds, s;
9024 
9025   PetscFunctionBegin;
9026   PetscCall(DMGetNumFields(dm, &Nf));
9027   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9028   PetscCall(DMGetNumDS(dm, &Nds));
9029   for (s = 0; s < Nds; ++s) {
9030     PetscDS         ds;
9031     DMLabel         label;
9032     IS              fieldIS;
9033     const PetscInt *fields;
9034     PetscInt        dsNf;
9035 
9036     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
9037     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9038     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9039     for (f = 0; f < dsNf; ++f) {
9040       const PetscInt field = fields[f];
9041       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9042     }
9043     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9044   }
9045   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);
9046   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9047   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9048   if (errorVec) {
9049     DM             edm;
9050     DMPolytopeType ct;
9051     PetscBool      simplex;
9052     PetscInt       dim, cStart, Nf;
9053 
9054     PetscCall(DMClone(dm, &edm));
9055     PetscCall(DMGetDimension(edm, &dim));
9056     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9057     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9058     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
9059     PetscCall(DMGetNumFields(dm, &Nf));
9060     for (f = 0; f < Nf; ++f) {
9061       PetscFE         fe, efe;
9062       PetscQuadrature q;
9063       const char     *name;
9064 
9065       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
9066       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9067       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
9068       PetscCall(PetscObjectSetName((PetscObject)efe, name));
9069       PetscCall(PetscFEGetQuadrature(fe, &q));
9070       PetscCall(PetscFESetQuadrature(efe, q));
9071       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
9072       PetscCall(PetscFEDestroy(&efe));
9073     }
9074     PetscCall(DMCreateDS(edm));
9075 
9076     PetscCall(DMCreateGlobalVector(edm, errorVec));
9077     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
9078     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9079     PetscCall(DMDestroy(&edm));
9080   }
9081   PetscCall(PetscFree2(exactSol, ctxs));
9082   PetscFunctionReturn(PETSC_SUCCESS);
9083 }
9084 
9085 /*@
9086   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
9087 
9088   Not Collective
9089 
9090   Input Parameter:
9091 . dm - The `DM`
9092 
9093   Output Parameter:
9094 . numAux - The number of auxiliary data vectors
9095 
9096   Level: advanced
9097 
9098 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
9099 @*/
9100 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9101 {
9102   PetscFunctionBegin;
9103   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9104   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9105   PetscFunctionReturn(PETSC_SUCCESS);
9106 }
9107 
9108 /*@
9109   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9110 
9111   Not Collective
9112 
9113   Input Parameters:
9114 + dm    - The `DM`
9115 . label - The `DMLabel`
9116 . value - The label value indicating the region
9117 - part  - The equation part, or 0 if unused
9118 
9119   Output Parameter:
9120 . aux - The `Vec` holding auxiliary field data
9121 
9122   Level: advanced
9123 
9124   Note:
9125   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9126 
9127 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
9128 @*/
9129 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9130 {
9131   PetscHashAuxKey key, wild = {NULL, 0, 0};
9132   PetscBool       has;
9133 
9134   PetscFunctionBegin;
9135   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9136   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9137   key.label = label;
9138   key.value = value;
9139   key.part  = part;
9140   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9141   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
9142   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9143   PetscFunctionReturn(PETSC_SUCCESS);
9144 }
9145 
9146 /*@
9147   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
9148 
9149   Not Collective because auxiliary vectors are not parallel
9150 
9151   Input Parameters:
9152 + dm    - The `DM`
9153 . label - The `DMLabel`
9154 . value - The label value indicating the region
9155 . part  - The equation part, or 0 if unused
9156 - aux   - The `Vec` holding auxiliary field data
9157 
9158   Level: advanced
9159 
9160 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
9161 @*/
9162 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9163 {
9164   Vec             old;
9165   PetscHashAuxKey key;
9166 
9167   PetscFunctionBegin;
9168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9169   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9170   key.label = label;
9171   key.value = value;
9172   key.part  = part;
9173   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9174   PetscCall(PetscObjectReference((PetscObject)aux));
9175   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9176   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9177   PetscCall(VecDestroy(&old));
9178   PetscFunctionReturn(PETSC_SUCCESS);
9179 }
9180 
9181 /*@
9182   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9183 
9184   Not Collective
9185 
9186   Input Parameter:
9187 . dm - The `DM`
9188 
9189   Output Parameters:
9190 + labels - The `DMLabel`s for each `Vec`
9191 . values - The label values for each `Vec`
9192 - parts  - The equation parts for each `Vec`
9193 
9194   Level: advanced
9195 
9196   Note:
9197   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9198 
9199 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9200 @*/
9201 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9202 {
9203   PetscHashAuxKey *keys;
9204   PetscInt         n, i, off = 0;
9205 
9206   PetscFunctionBegin;
9207   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9208   PetscAssertPointer(labels, 2);
9209   PetscAssertPointer(values, 3);
9210   PetscAssertPointer(parts, 4);
9211   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9212   PetscCall(PetscMalloc1(n, &keys));
9213   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9214   for (i = 0; i < n; ++i) {
9215     labels[i] = keys[i].label;
9216     values[i] = keys[i].value;
9217     parts[i]  = keys[i].part;
9218   }
9219   PetscCall(PetscFree(keys));
9220   PetscFunctionReturn(PETSC_SUCCESS);
9221 }
9222 
9223 /*@
9224   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9225 
9226   Not Collective
9227 
9228   Input Parameter:
9229 . dm - The `DM`
9230 
9231   Output Parameter:
9232 . dmNew - The new `DM`, now with the same auxiliary data
9233 
9234   Level: advanced
9235 
9236   Note:
9237   This is a shallow copy of the auxiliary vectors
9238 
9239 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9240 @*/
9241 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9242 {
9243   PetscFunctionBegin;
9244   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9245   PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2);
9246   if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS);
9247   PetscCall(DMClearAuxiliaryVec(dmNew));
9248 
9249   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9250   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9251   {
9252     Vec     *auxData;
9253     PetscInt n, i, off = 0;
9254 
9255     PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n));
9256     PetscCall(PetscMalloc1(n, &auxData));
9257     PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData));
9258     for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i]));
9259     PetscCall(PetscFree(auxData));
9260   }
9261   PetscFunctionReturn(PETSC_SUCCESS);
9262 }
9263 
9264 /*@
9265   DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one
9266 
9267   Not Collective
9268 
9269   Input Parameter:
9270 . dm - The `DM`
9271 
9272   Level: advanced
9273 
9274 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9275 @*/
9276 PetscErrorCode DMClearAuxiliaryVec(DM dm)
9277 {
9278   Vec     *auxData;
9279   PetscInt n, i, off = 0;
9280 
9281   PetscFunctionBegin;
9282   PetscCall(PetscHMapAuxGetSize(dm->auxData, &n));
9283   PetscCall(PetscMalloc1(n, &auxData));
9284   PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData));
9285   for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i]));
9286   PetscCall(PetscFree(auxData));
9287   PetscCall(PetscHMapAuxDestroy(&dm->auxData));
9288   PetscCall(PetscHMapAuxCreate(&dm->auxData));
9289   PetscFunctionReturn(PETSC_SUCCESS);
9290 }
9291 
9292 /*@
9293   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9294 
9295   Not Collective
9296 
9297   Input Parameters:
9298 + ct         - The `DMPolytopeType`
9299 . sourceCone - The source arrangement of faces
9300 - targetCone - The target arrangement of faces
9301 
9302   Output Parameters:
9303 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9304 - found - Flag indicating that a suitable orientation was found
9305 
9306   Level: advanced
9307 
9308   Note:
9309   An arrangement is a face order combined with an orientation for each face
9310 
9311   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9312   that labels each arrangement (face ordering plus orientation for each face).
9313 
9314   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9315 
9316 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9317 @*/
9318 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9319 {
9320   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9321   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9322   PetscInt       o, c;
9323 
9324   PetscFunctionBegin;
9325   if (!nO) {
9326     *ornt  = 0;
9327     *found = PETSC_TRUE;
9328     PetscFunctionReturn(PETSC_SUCCESS);
9329   }
9330   for (o = -nO; o < nO; ++o) {
9331     const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o);
9332 
9333     for (c = 0; c < cS; ++c)
9334       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9335     if (c == cS) {
9336       *ornt = o;
9337       break;
9338     }
9339   }
9340   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9341   PetscFunctionReturn(PETSC_SUCCESS);
9342 }
9343 
9344 /*@
9345   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9346 
9347   Not Collective
9348 
9349   Input Parameters:
9350 + ct         - The `DMPolytopeType`
9351 . sourceCone - The source arrangement of faces
9352 - targetCone - The target arrangement of faces
9353 
9354   Output Parameter:
9355 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9356 
9357   Level: advanced
9358 
9359   Note:
9360   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9361 
9362   Developer Note:
9363   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9364 
9365 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9366 @*/
9367 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9368 {
9369   PetscBool found;
9370 
9371   PetscFunctionBegin;
9372   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9373   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9374   PetscFunctionReturn(PETSC_SUCCESS);
9375 }
9376 
9377 /*@
9378   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9379 
9380   Not Collective
9381 
9382   Input Parameters:
9383 + ct         - The `DMPolytopeType`
9384 . sourceVert - The source arrangement of vertices
9385 - targetVert - The target arrangement of vertices
9386 
9387   Output Parameters:
9388 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9389 - found - Flag indicating that a suitable orientation was found
9390 
9391   Level: advanced
9392 
9393   Notes:
9394   An arrangement is a vertex order
9395 
9396   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2
9397   that labels each arrangement (vertex ordering).
9398 
9399   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9400 
9401 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()`
9402 @*/
9403 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9404 {
9405   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9406   const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2;
9407   PetscInt       o, c;
9408 
9409   PetscFunctionBegin;
9410   if (!nO) {
9411     *ornt  = 0;
9412     *found = PETSC_TRUE;
9413     PetscFunctionReturn(PETSC_SUCCESS);
9414   }
9415   for (o = -nO; o < nO; ++o) {
9416     const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o);
9417 
9418     for (c = 0; c < cS; ++c)
9419       if (sourceVert[arr[c]] != targetVert[c]) break;
9420     if (c == cS) {
9421       *ornt = o;
9422       break;
9423     }
9424   }
9425   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9426   PetscFunctionReturn(PETSC_SUCCESS);
9427 }
9428 
9429 /*@
9430   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9431 
9432   Not Collective
9433 
9434   Input Parameters:
9435 + ct         - The `DMPolytopeType`
9436 . sourceCone - The source arrangement of vertices
9437 - targetCone - The target arrangement of vertices
9438 
9439   Output Parameter:
9440 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9441 
9442   Level: advanced
9443 
9444   Note:
9445   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9446 
9447   Developer Note:
9448   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9449 
9450 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9451 @*/
9452 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9453 {
9454   PetscBool found;
9455 
9456   PetscFunctionBegin;
9457   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9458   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9459   PetscFunctionReturn(PETSC_SUCCESS);
9460 }
9461 
9462 /*@
9463   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9464 
9465   Not Collective
9466 
9467   Input Parameters:
9468 + ct    - The `DMPolytopeType`
9469 - point - Coordinates of the point
9470 
9471   Output Parameter:
9472 . inside - Flag indicating whether the point is inside the reference cell of given type
9473 
9474   Level: advanced
9475 
9476 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9477 @*/
9478 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9479 {
9480   PetscReal sum = 0.0;
9481   PetscInt  d;
9482 
9483   PetscFunctionBegin;
9484   *inside = PETSC_TRUE;
9485   switch (ct) {
9486   case DM_POLYTOPE_TRIANGLE:
9487   case DM_POLYTOPE_TETRAHEDRON:
9488     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9489       if (point[d] < -1.0) {
9490         *inside = PETSC_FALSE;
9491         break;
9492       }
9493       sum += point[d];
9494     }
9495     if (sum > PETSC_SMALL) {
9496       *inside = PETSC_FALSE;
9497       break;
9498     }
9499     break;
9500   case DM_POLYTOPE_QUADRILATERAL:
9501   case DM_POLYTOPE_HEXAHEDRON:
9502     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9503       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9504         *inside = PETSC_FALSE;
9505         break;
9506       }
9507     break;
9508   default:
9509     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9510   }
9511   PetscFunctionReturn(PETSC_SUCCESS);
9512 }
9513 
9514 /*@
9515   DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default
9516 
9517   Logically collective
9518 
9519   Input Parameters:
9520 + dm      - The DM
9521 - reorder - Flag for reordering
9522 
9523   Level: intermediate
9524 
9525 .seealso: `DMReorderSectionGetDefault()`
9526 @*/
9527 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder)
9528 {
9529   PetscFunctionBegin;
9530   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9531   PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder));
9532   PetscFunctionReturn(PETSC_SUCCESS);
9533 }
9534 
9535 /*@
9536   DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default
9537 
9538   Not collective
9539 
9540   Input Parameter:
9541 . dm - The DM
9542 
9543   Output Parameter:
9544 . reorder - Flag for reordering
9545 
9546   Level: intermediate
9547 
9548 .seealso: `DMReorderSetDefault()`
9549 @*/
9550 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder)
9551 {
9552   PetscFunctionBegin;
9553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9554   PetscAssertPointer(reorder, 2);
9555   *reorder = DM_REORDER_DEFAULT_NOTSET;
9556   PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder));
9557   PetscFunctionReturn(PETSC_SUCCESS);
9558 }
9559 
9560 /*@
9561   DMReorderSectionSetType - Set the type of local section reordering
9562 
9563   Logically collective
9564 
9565   Input Parameters:
9566 + dm      - The DM
9567 - reorder - The reordering method
9568 
9569   Level: intermediate
9570 
9571 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()`
9572 @*/
9573 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder)
9574 {
9575   PetscFunctionBegin;
9576   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9577   PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder));
9578   PetscFunctionReturn(PETSC_SUCCESS);
9579 }
9580 
9581 /*@
9582   DMReorderSectionGetType - Get the reordering type for the local section
9583 
9584   Not collective
9585 
9586   Input Parameter:
9587 . dm - The DM
9588 
9589   Output Parameter:
9590 . reorder - The reordering method
9591 
9592   Level: intermediate
9593 
9594 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()`
9595 @*/
9596 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder)
9597 {
9598   PetscFunctionBegin;
9599   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9600   PetscAssertPointer(reorder, 2);
9601   *reorder = NULL;
9602   PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder));
9603   PetscFunctionReturn(PETSC_SUCCESS);
9604 }
9605