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