xref: /petsc/src/dm/interface/dm.c (revision d529f056d75cd16b380adc3e50ccb741df53d0de)
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 static 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 DMPrintCellIndices(PetscInt c, const char name[], PetscInt len, const PetscInt 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, "  | %" PetscInt_FMT " |\n", x[f]));
4143   PetscFunctionReturn(PETSC_SUCCESS);
4144 }
4145 
4146 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
4147 {
4148   PetscInt f;
4149 
4150   PetscFunctionBegin;
4151   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4152   for (f = 0; f < len; ++f) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f])));
4153   PetscFunctionReturn(PETSC_SUCCESS);
4154 }
4155 
4156 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
4157 {
4158   PetscInt f, g;
4159 
4160   PetscFunctionBegin;
4161   PetscCall(PetscPrintf(PETSC_COMM_SELF, "Cell %" PetscInt_FMT " Element %s\n", c, name));
4162   for (f = 0; f < rows; ++f) {
4163     PetscCall(PetscPrintf(PETSC_COMM_SELF, "  |"));
4164     for (g = 0; g < cols; ++g) PetscCall(PetscPrintf(PETSC_COMM_SELF, " % 9.5g", (double)PetscRealPart(A[f * cols + g])));
4165     PetscCall(PetscPrintf(PETSC_COMM_SELF, " |\n"));
4166   }
4167   PetscFunctionReturn(PETSC_SUCCESS);
4168 }
4169 
4170 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
4171 {
4172   PetscInt           localSize, bs;
4173   PetscMPIInt        size;
4174   Vec                x, xglob;
4175   const PetscScalar *xarray;
4176 
4177   PetscFunctionBegin;
4178   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
4179   PetscCall(VecDuplicate(X, &x));
4180   PetscCall(VecCopy(X, x));
4181   PetscCall(VecFilter(x, tol));
4182   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "%s:\n", name));
4183   if (size > 1) {
4184     PetscCall(VecGetLocalSize(x, &localSize));
4185     PetscCall(VecGetArrayRead(x, &xarray));
4186     PetscCall(VecGetBlockSize(x, &bs));
4187     PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)dm), bs, localSize, PETSC_DETERMINE, xarray, &xglob));
4188   } else {
4189     xglob = x;
4190   }
4191   PetscCall(VecView(xglob, PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)dm))));
4192   if (size > 1) {
4193     PetscCall(VecDestroy(&xglob));
4194     PetscCall(VecRestoreArrayRead(x, &xarray));
4195   }
4196   PetscCall(VecDestroy(&x));
4197   PetscFunctionReturn(PETSC_SUCCESS);
4198 }
4199 
4200 /*@
4201   DMGetSection - Get the `PetscSection` encoding the local data layout for the `DM`.   This is equivalent to `DMGetLocalSection()`. Deprecated in v3.12
4202 
4203   Input Parameter:
4204 . dm - The `DM`
4205 
4206   Output Parameter:
4207 . section - The `PetscSection`
4208 
4209   Options Database Key:
4210 . -dm_petscsection_view - View the `PetscSection` created by the `DM`
4211 
4212   Level: advanced
4213 
4214   Notes:
4215   Use `DMGetLocalSection()` in new code.
4216 
4217   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4218 
4219 .seealso: [](ch_dmbase), `DM`, `DMGetLocalSection()`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4220 @*/
4221 PetscErrorCode DMGetSection(DM dm, PetscSection *section)
4222 {
4223   PetscFunctionBegin;
4224   PetscCall(DMGetLocalSection(dm, section));
4225   PetscFunctionReturn(PETSC_SUCCESS);
4226 }
4227 
4228 /*@
4229   DMGetLocalSection - Get the `PetscSection` encoding the local data layout for the `DM`.
4230 
4231   Input Parameter:
4232 . dm - The `DM`
4233 
4234   Output Parameter:
4235 . section - The `PetscSection`
4236 
4237   Options Database Key:
4238 . -dm_petscsection_view - View the section created by the `DM`
4239 
4240   Level: intermediate
4241 
4242   Note:
4243   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4244 
4245 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetGlobalSection()`
4246 @*/
4247 PetscErrorCode DMGetLocalSection(DM dm, PetscSection *section)
4248 {
4249   PetscFunctionBegin;
4250   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4251   PetscAssertPointer(section, 2);
4252   if (!dm->localSection && dm->ops->createlocalsection) {
4253     PetscInt d;
4254 
4255     if (dm->setfromoptionscalled) {
4256       PetscObject       obj = (PetscObject)dm;
4257       PetscViewer       viewer;
4258       PetscViewerFormat format;
4259       PetscBool         flg;
4260 
4261       PetscCall(PetscOptionsGetViewer(PetscObjectComm(obj), obj->options, obj->prefix, "-dm_petscds_view", &viewer, &format, &flg));
4262       if (flg) PetscCall(PetscViewerPushFormat(viewer, format));
4263       for (d = 0; d < dm->Nds; ++d) {
4264         PetscCall(PetscDSSetFromOptions(dm->probs[d].ds));
4265         if (flg) PetscCall(PetscDSView(dm->probs[d].ds, viewer));
4266       }
4267       if (flg) {
4268         PetscCall(PetscViewerFlush(viewer));
4269         PetscCall(PetscViewerPopFormat(viewer));
4270         PetscCall(PetscViewerDestroy(&viewer));
4271       }
4272     }
4273     PetscUseTypeMethod(dm, createlocalsection);
4274     if (dm->localSection) PetscCall(PetscObjectViewFromOptions((PetscObject)dm->localSection, NULL, "-dm_petscsection_view"));
4275   }
4276   *section = dm->localSection;
4277   PetscFunctionReturn(PETSC_SUCCESS);
4278 }
4279 
4280 /*@
4281   DMSetSection - Set the `PetscSection` encoding the local data layout for the `DM`.  This is equivalent to `DMSetLocalSection()`. Deprecated in v3.12
4282 
4283   Input Parameters:
4284 + dm      - The `DM`
4285 - section - The `PetscSection`
4286 
4287   Level: advanced
4288 
4289   Notes:
4290   Use `DMSetLocalSection()` in new code.
4291 
4292   Any existing `PetscSection` will be destroyed
4293 
4294 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4295 @*/
4296 PetscErrorCode DMSetSection(DM dm, PetscSection section)
4297 {
4298   PetscFunctionBegin;
4299   PetscCall(DMSetLocalSection(dm, section));
4300   PetscFunctionReturn(PETSC_SUCCESS);
4301 }
4302 
4303 /*@
4304   DMSetLocalSection - Set the `PetscSection` encoding the local data layout for the `DM`.
4305 
4306   Input Parameters:
4307 + dm      - The `DM`
4308 - section - The `PetscSection`
4309 
4310   Level: intermediate
4311 
4312   Note:
4313   Any existing Section will be destroyed
4314 
4315 .seealso: [](ch_dmbase), `DM`, `PetscSection`, `DMGetLocalSection()`, `DMSetGlobalSection()`
4316 @*/
4317 PetscErrorCode DMSetLocalSection(DM dm, PetscSection section)
4318 {
4319   PetscInt numFields = 0;
4320   PetscInt f;
4321 
4322   PetscFunctionBegin;
4323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4324   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4325   PetscCall(PetscObjectReference((PetscObject)section));
4326   PetscCall(PetscSectionDestroy(&dm->localSection));
4327   dm->localSection = section;
4328   if (section) PetscCall(PetscSectionGetNumFields(dm->localSection, &numFields));
4329   if (numFields) {
4330     PetscCall(DMSetNumFields(dm, numFields));
4331     for (f = 0; f < numFields; ++f) {
4332       PetscObject disc;
4333       const char *name;
4334 
4335       PetscCall(PetscSectionGetFieldName(dm->localSection, f, &name));
4336       PetscCall(DMGetField(dm, f, NULL, &disc));
4337       PetscCall(PetscObjectSetName(disc, name));
4338     }
4339   }
4340   /* The global section will be rebuilt in the next call to DMGetGlobalSection(). */
4341   PetscCall(PetscSectionDestroy(&dm->globalSection));
4342   PetscFunctionReturn(PETSC_SUCCESS);
4343 }
4344 
4345 /*@
4346   DMGetDefaultConstraints - Get the `PetscSection` and `Mat` that specify the local constraint interpolation. See `DMSetDefaultConstraints()` for a description of the purpose of constraint interpolation.
4347 
4348   not Collective
4349 
4350   Input Parameter:
4351 . dm - The `DM`
4352 
4353   Output Parameters:
4354 + 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.
4355 . 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.
4356 - bias    - Vector containing bias to be added to constrained dofs
4357 
4358   Level: advanced
4359 
4360   Note:
4361   This gets borrowed references, so the user should not destroy the `PetscSection`, `Mat`, or `Vec`.
4362 
4363 .seealso: [](ch_dmbase), `DM`, `DMSetDefaultConstraints()`
4364 @*/
4365 PetscErrorCode DMGetDefaultConstraints(DM dm, PetscSection *section, Mat *mat, Vec *bias)
4366 {
4367   PetscFunctionBegin;
4368   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4369   if (!dm->defaultConstraint.section && !dm->defaultConstraint.mat && dm->ops->createdefaultconstraints) PetscUseTypeMethod(dm, createdefaultconstraints);
4370   if (section) *section = dm->defaultConstraint.section;
4371   if (mat) *mat = dm->defaultConstraint.mat;
4372   if (bias) *bias = dm->defaultConstraint.bias;
4373   PetscFunctionReturn(PETSC_SUCCESS);
4374 }
4375 
4376 /*@
4377   DMSetDefaultConstraints - Set the `PetscSection` and `Mat` that specify the local constraint interpolation.
4378 
4379   Collective
4380 
4381   Input Parameters:
4382 + dm      - The `DM`
4383 . 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).
4384 . 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).
4385 - 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).
4386 
4387   Level: advanced
4388 
4389   Notes:
4390   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()`.
4391 
4392   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.
4393 
4394   This increments the references of the `PetscSection`, `Mat`, and `Vec`, so they user can destroy them.
4395 
4396 .seealso: [](ch_dmbase), `DM`, `DMGetDefaultConstraints()`
4397 @*/
4398 PetscErrorCode DMSetDefaultConstraints(DM dm, PetscSection section, Mat mat, Vec bias)
4399 {
4400   PetscMPIInt result;
4401 
4402   PetscFunctionBegin;
4403   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4404   if (section) {
4405     PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4406     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)section), &result));
4407     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint section must have local communicator");
4408   }
4409   if (mat) {
4410     PetscValidHeaderSpecific(mat, MAT_CLASSID, 3);
4411     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)mat), &result));
4412     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint matrix must have local communicator");
4413   }
4414   if (bias) {
4415     PetscValidHeaderSpecific(bias, VEC_CLASSID, 4);
4416     PetscCallMPI(MPI_Comm_compare(PETSC_COMM_SELF, PetscObjectComm((PetscObject)bias), &result));
4417     PetscCheck(result == MPI_CONGRUENT || result == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "constraint bias must have local communicator");
4418   }
4419   PetscCall(PetscObjectReference((PetscObject)section));
4420   PetscCall(PetscSectionDestroy(&dm->defaultConstraint.section));
4421   dm->defaultConstraint.section = section;
4422   PetscCall(PetscObjectReference((PetscObject)mat));
4423   PetscCall(MatDestroy(&dm->defaultConstraint.mat));
4424   dm->defaultConstraint.mat = mat;
4425   PetscCall(PetscObjectReference((PetscObject)bias));
4426   PetscCall(VecDestroy(&dm->defaultConstraint.bias));
4427   dm->defaultConstraint.bias = bias;
4428   PetscFunctionReturn(PETSC_SUCCESS);
4429 }
4430 
4431 #if defined(PETSC_USE_DEBUG)
4432 /*
4433   DMDefaultSectionCheckConsistency - Check the consistentcy of the global and local sections. Generates and error if they are not consistent.
4434 
4435   Input Parameters:
4436 + dm - The `DM`
4437 . localSection - `PetscSection` describing the local data layout
4438 - globalSection - `PetscSection` describing the global data layout
4439 
4440   Level: intermediate
4441 
4442 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`
4443 */
4444 static PetscErrorCode DMDefaultSectionCheckConsistency_Internal(DM dm, PetscSection localSection, PetscSection globalSection)
4445 {
4446   MPI_Comm        comm;
4447   PetscLayout     layout;
4448   const PetscInt *ranges;
4449   PetscInt        pStart, pEnd, p, nroots;
4450   PetscMPIInt     size, rank;
4451   PetscBool       valid = PETSC_TRUE, gvalid;
4452 
4453   PetscFunctionBegin;
4454   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
4455   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4456   PetscCallMPI(MPI_Comm_size(comm, &size));
4457   PetscCallMPI(MPI_Comm_rank(comm, &rank));
4458   PetscCall(PetscSectionGetChart(globalSection, &pStart, &pEnd));
4459   PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &nroots));
4460   PetscCall(PetscLayoutCreate(comm, &layout));
4461   PetscCall(PetscLayoutSetBlockSize(layout, 1));
4462   PetscCall(PetscLayoutSetLocalSize(layout, nroots));
4463   PetscCall(PetscLayoutSetUp(layout));
4464   PetscCall(PetscLayoutGetRanges(layout, &ranges));
4465   for (p = pStart; p < pEnd; ++p) {
4466     PetscInt dof, cdof, off, gdof, gcdof, goff, gsize, d;
4467 
4468     PetscCall(PetscSectionGetDof(localSection, p, &dof));
4469     PetscCall(PetscSectionGetOffset(localSection, p, &off));
4470     PetscCall(PetscSectionGetConstraintDof(localSection, p, &cdof));
4471     PetscCall(PetscSectionGetDof(globalSection, p, &gdof));
4472     PetscCall(PetscSectionGetConstraintDof(globalSection, p, &gcdof));
4473     PetscCall(PetscSectionGetOffset(globalSection, p, &goff));
4474     if (!gdof) continue; /* Censored point */
4475     if ((gdof < 0 ? -(gdof + 1) : gdof) != dof) {
4476       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global dof %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local dof %" PetscInt_FMT "\n", rank, gdof, p, dof));
4477       valid = PETSC_FALSE;
4478     }
4479     if (gcdof && (gcdof != cdof)) {
4480       PetscCall(PetscSynchronizedPrintf(comm, "[%d]Global constraints %" PetscInt_FMT " for point %" PetscInt_FMT " not equal to local constraints %" PetscInt_FMT "\n", rank, gcdof, p, cdof));
4481       valid = PETSC_FALSE;
4482     }
4483     if (gdof < 0) {
4484       gsize = gdof < 0 ? -(gdof + 1) - gcdof : gdof - gcdof;
4485       for (d = 0; d < gsize; ++d) {
4486         PetscInt offset = -(goff + 1) + d, r;
4487 
4488         PetscCall(PetscFindInt(offset, size + 1, ranges, &r));
4489         if (r < 0) r = -(r + 2);
4490         if ((r < 0) || (r >= size)) {
4491           PetscCall(PetscSynchronizedPrintf(comm, "[%d]Point %" PetscInt_FMT " mapped to invalid process %" PetscInt_FMT " (%" PetscInt_FMT ", %" PetscInt_FMT ")\n", rank, p, r, gdof, goff));
4492           valid = PETSC_FALSE;
4493           break;
4494         }
4495       }
4496     }
4497   }
4498   PetscCall(PetscLayoutDestroy(&layout));
4499   PetscCall(PetscSynchronizedFlush(comm, NULL));
4500   PetscCall(MPIU_Allreduce(&valid, &gvalid, 1, MPIU_BOOL, MPI_LAND, comm));
4501   if (!gvalid) {
4502     PetscCall(DMView(dm, NULL));
4503     SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Inconsistent local and global sections");
4504   }
4505   PetscFunctionReturn(PETSC_SUCCESS);
4506 }
4507 #endif
4508 
4509 static PetscErrorCode DMGetIsoperiodicPointSF_Internal(DM dm, PetscSF *sf)
4510 {
4511   PetscErrorCode (*f)(DM, PetscSF *);
4512   PetscFunctionBegin;
4513   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4514   PetscAssertPointer(sf, 2);
4515   PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f));
4516   if (f) PetscCall(f(dm, sf));
4517   else *sf = dm->sf;
4518   PetscFunctionReturn(PETSC_SUCCESS);
4519 }
4520 
4521 /*@
4522   DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`.
4523 
4524   Collective
4525 
4526   Input Parameter:
4527 . dm - The `DM`
4528 
4529   Output Parameter:
4530 . section - The `PetscSection`
4531 
4532   Level: intermediate
4533 
4534   Note:
4535   This gets a borrowed reference, so the user should not destroy this `PetscSection`.
4536 
4537 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()`
4538 @*/
4539 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section)
4540 {
4541   PetscFunctionBegin;
4542   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4543   PetscAssertPointer(section, 2);
4544   if (!dm->globalSection) {
4545     PetscSection s;
4546     PetscSF      sf;
4547 
4548     PetscCall(DMGetLocalSection(dm, &s));
4549     PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
4550     PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection");
4551     PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf));
4552     PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_FALSE, PETSC_FALSE, &dm->globalSection));
4553     PetscCall(PetscLayoutDestroy(&dm->map));
4554     PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map));
4555     PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view"));
4556   }
4557   *section = dm->globalSection;
4558   PetscFunctionReturn(PETSC_SUCCESS);
4559 }
4560 
4561 /*@
4562   DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`.
4563 
4564   Input Parameters:
4565 + dm      - The `DM`
4566 - section - The PetscSection, or `NULL`
4567 
4568   Level: intermediate
4569 
4570   Note:
4571   Any existing `PetscSection` will be destroyed
4572 
4573 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()`
4574 @*/
4575 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section)
4576 {
4577   PetscFunctionBegin;
4578   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4579   if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2);
4580   PetscCall(PetscObjectReference((PetscObject)section));
4581   PetscCall(PetscSectionDestroy(&dm->globalSection));
4582   dm->globalSection = section;
4583 #if defined(PETSC_USE_DEBUG)
4584   if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section));
4585 #endif
4586   PetscFunctionReturn(PETSC_SUCCESS);
4587 }
4588 
4589 /*@
4590   DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set,
4591   it is created from the default `PetscSection` layouts in the `DM`.
4592 
4593   Input Parameter:
4594 . dm - The `DM`
4595 
4596   Output Parameter:
4597 . sf - The `PetscSF`
4598 
4599   Level: intermediate
4600 
4601   Note:
4602   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4603 
4604 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4605 @*/
4606 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf)
4607 {
4608   PetscInt nroots;
4609 
4610   PetscFunctionBegin;
4611   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4612   PetscAssertPointer(sf, 2);
4613   if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF));
4614   PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL));
4615   if (nroots < 0) {
4616     PetscSection section, gSection;
4617 
4618     PetscCall(DMGetLocalSection(dm, &section));
4619     if (section) {
4620       PetscCall(DMGetGlobalSection(dm, &gSection));
4621       PetscCall(DMCreateSectionSF(dm, section, gSection));
4622     } else {
4623       *sf = NULL;
4624       PetscFunctionReturn(PETSC_SUCCESS);
4625     }
4626   }
4627   *sf = dm->sectionSF;
4628   PetscFunctionReturn(PETSC_SUCCESS);
4629 }
4630 
4631 /*@
4632   DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM`
4633 
4634   Input Parameters:
4635 + dm - The `DM`
4636 - sf - The `PetscSF`
4637 
4638   Level: intermediate
4639 
4640   Note:
4641   Any previous `PetscSF` is destroyed
4642 
4643 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()`
4644 @*/
4645 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf)
4646 {
4647   PetscFunctionBegin;
4648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4649   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4650   PetscCall(PetscObjectReference((PetscObject)sf));
4651   PetscCall(PetscSFDestroy(&dm->sectionSF));
4652   dm->sectionSF = sf;
4653   PetscFunctionReturn(PETSC_SUCCESS);
4654 }
4655 
4656 /*@C
4657   DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s
4658   describing the data layout.
4659 
4660   Input Parameters:
4661 + dm            - The `DM`
4662 . localSection  - `PetscSection` describing the local data layout
4663 - globalSection - `PetscSection` describing the global data layout
4664 
4665   Level: developer
4666 
4667   Note:
4668   One usually uses `DMGetSectionSF()` to obtain the `PetscSF`
4669 
4670   Developer Notes:
4671   Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF`
4672   directly into the `DM`, perhaps this function should not take the local and global sections as
4673   input and should just obtain them from the `DM`?
4674 
4675 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()`
4676 @*/
4677 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection)
4678 {
4679   PetscFunctionBegin;
4680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4681   PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection));
4682   PetscFunctionReturn(PETSC_SUCCESS);
4683 }
4684 
4685 /*@
4686   DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`.
4687 
4688   Not collective but the resulting `PetscSF` is collective
4689 
4690   Input Parameter:
4691 . dm - The `DM`
4692 
4693   Output Parameter:
4694 . sf - The `PetscSF`
4695 
4696   Level: intermediate
4697 
4698   Note:
4699   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4700 
4701 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4702 @*/
4703 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4704 {
4705   PetscFunctionBegin;
4706   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4707   PetscAssertPointer(sf, 2);
4708   *sf = dm->sf;
4709   PetscFunctionReturn(PETSC_SUCCESS);
4710 }
4711 
4712 /*@
4713   DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`.
4714 
4715   Collective
4716 
4717   Input Parameters:
4718 + dm - The `DM`
4719 - sf - The `PetscSF`
4720 
4721   Level: intermediate
4722 
4723 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()`
4724 @*/
4725 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4726 {
4727   PetscFunctionBegin;
4728   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4729   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4730   PetscCall(PetscObjectReference((PetscObject)sf));
4731   PetscCall(PetscSFDestroy(&dm->sf));
4732   dm->sf = sf;
4733   PetscFunctionReturn(PETSC_SUCCESS);
4734 }
4735 
4736 /*@
4737   DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering
4738 
4739   Input Parameter:
4740 . dm - The `DM`
4741 
4742   Output Parameter:
4743 . sf - The `PetscSF`
4744 
4745   Level: intermediate
4746 
4747   Note:
4748   This gets a borrowed reference, so the user should not destroy this `PetscSF`.
4749 
4750 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4751 @*/
4752 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf)
4753 {
4754   PetscFunctionBegin;
4755   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4756   PetscAssertPointer(sf, 2);
4757   *sf = dm->sfNatural;
4758   PetscFunctionReturn(PETSC_SUCCESS);
4759 }
4760 
4761 /*@
4762   DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering
4763 
4764   Input Parameters:
4765 + dm - The DM
4766 - sf - The PetscSF
4767 
4768   Level: intermediate
4769 
4770 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()`
4771 @*/
4772 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf)
4773 {
4774   PetscFunctionBegin;
4775   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4776   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4777   PetscCall(PetscObjectReference((PetscObject)sf));
4778   PetscCall(PetscSFDestroy(&dm->sfNatural));
4779   dm->sfNatural = sf;
4780   PetscFunctionReturn(PETSC_SUCCESS);
4781 }
4782 
4783 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4784 {
4785   PetscClassId id;
4786 
4787   PetscFunctionBegin;
4788   PetscCall(PetscObjectGetClassId(disc, &id));
4789   if (id == PETSCFE_CLASSID) {
4790     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4791   } else if (id == PETSCFV_CLASSID) {
4792     PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE));
4793   } else {
4794     PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE));
4795   }
4796   PetscFunctionReturn(PETSC_SUCCESS);
4797 }
4798 
4799 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4800 {
4801   RegionField *tmpr;
4802   PetscInt     Nf = dm->Nf, f;
4803 
4804   PetscFunctionBegin;
4805   if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS);
4806   PetscCall(PetscMalloc1(NfNew, &tmpr));
4807   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4808   for (f = Nf; f < NfNew; ++f) {
4809     tmpr[f].disc        = NULL;
4810     tmpr[f].label       = NULL;
4811     tmpr[f].avoidTensor = PETSC_FALSE;
4812   }
4813   PetscCall(PetscFree(dm->fields));
4814   dm->Nf     = NfNew;
4815   dm->fields = tmpr;
4816   PetscFunctionReturn(PETSC_SUCCESS);
4817 }
4818 
4819 /*@
4820   DMClearFields - Remove all fields from the `DM`
4821 
4822   Logically Collective
4823 
4824   Input Parameter:
4825 . dm - The `DM`
4826 
4827   Level: intermediate
4828 
4829 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()`
4830 @*/
4831 PetscErrorCode DMClearFields(DM dm)
4832 {
4833   PetscInt f;
4834 
4835   PetscFunctionBegin;
4836   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4837   for (f = 0; f < dm->Nf; ++f) {
4838     PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4839     PetscCall(DMLabelDestroy(&dm->fields[f].label));
4840   }
4841   PetscCall(PetscFree(dm->fields));
4842   dm->fields = NULL;
4843   dm->Nf     = 0;
4844   PetscFunctionReturn(PETSC_SUCCESS);
4845 }
4846 
4847 /*@
4848   DMGetNumFields - Get the number of fields in the `DM`
4849 
4850   Not Collective
4851 
4852   Input Parameter:
4853 . dm - The `DM`
4854 
4855   Output Parameter:
4856 . numFields - The number of fields
4857 
4858   Level: intermediate
4859 
4860 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()`
4861 @*/
4862 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4863 {
4864   PetscFunctionBegin;
4865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4866   PetscAssertPointer(numFields, 2);
4867   *numFields = dm->Nf;
4868   PetscFunctionReturn(PETSC_SUCCESS);
4869 }
4870 
4871 /*@
4872   DMSetNumFields - Set the number of fields in the `DM`
4873 
4874   Logically Collective
4875 
4876   Input Parameters:
4877 + dm        - The `DM`
4878 - numFields - The number of fields
4879 
4880   Level: intermediate
4881 
4882 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()`
4883 @*/
4884 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4885 {
4886   PetscInt Nf, f;
4887 
4888   PetscFunctionBegin;
4889   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4890   PetscCall(DMGetNumFields(dm, &Nf));
4891   for (f = Nf; f < numFields; ++f) {
4892     PetscContainer obj;
4893 
4894     PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj));
4895     PetscCall(DMAddField(dm, NULL, (PetscObject)obj));
4896     PetscCall(PetscContainerDestroy(&obj));
4897   }
4898   PetscFunctionReturn(PETSC_SUCCESS);
4899 }
4900 
4901 /*@
4902   DMGetField - Return the `DMLabel` and discretization object for a given `DM` field
4903 
4904   Not Collective
4905 
4906   Input Parameters:
4907 + dm - The `DM`
4908 - f  - The field number
4909 
4910   Output Parameters:
4911 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed)
4912 - disc  - The discretization object (pass in `NULL` if not needed)
4913 
4914   Level: intermediate
4915 
4916 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`
4917 @*/
4918 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc)
4919 {
4920   PetscFunctionBegin;
4921   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4922   PetscAssertPointer(disc, 4);
4923   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);
4924   if (label) *label = dm->fields[f].label;
4925   if (disc) *disc = dm->fields[f].disc;
4926   PetscFunctionReturn(PETSC_SUCCESS);
4927 }
4928 
4929 /* Does not clear the DS */
4930 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4931 {
4932   PetscFunctionBegin;
4933   PetscCall(DMFieldEnlarge_Static(dm, f + 1));
4934   PetscCall(DMLabelDestroy(&dm->fields[f].label));
4935   PetscCall(PetscObjectDestroy(&dm->fields[f].disc));
4936   dm->fields[f].label = label;
4937   dm->fields[f].disc  = disc;
4938   PetscCall(PetscObjectReference((PetscObject)label));
4939   PetscCall(PetscObjectReference((PetscObject)disc));
4940   PetscFunctionReturn(PETSC_SUCCESS);
4941 }
4942 
4943 /*@C
4944   DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles
4945   the field numbering.
4946 
4947   Logically Collective
4948 
4949   Input Parameters:
4950 + dm    - The `DM`
4951 . f     - The field number
4952 . label - The label indicating the support of the field, or `NULL` for the entire mesh
4953 - disc  - The discretization object
4954 
4955   Level: intermediate
4956 
4957 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()`
4958 @*/
4959 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc)
4960 {
4961   PetscFunctionBegin;
4962   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4963   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4964   PetscValidHeader(disc, 4);
4965   PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f);
4966   PetscCall(DMSetField_Internal(dm, f, label, disc));
4967   PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc));
4968   PetscCall(DMClearDS(dm));
4969   PetscFunctionReturn(PETSC_SUCCESS);
4970 }
4971 
4972 /*@C
4973   DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities)
4974   and a discretization object that defines the function space associated with those points.
4975 
4976   Logically Collective
4977 
4978   Input Parameters:
4979 + dm    - The `DM`
4980 . label - The label indicating the support of the field, or `NULL` for the entire mesh
4981 - disc  - The discretization object
4982 
4983   Level: intermediate
4984 
4985   Notes:
4986   The label already exists or will be added to the `DM` with `DMSetLabel()`.
4987 
4988   For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions
4989   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
4990   geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`.
4991 
4992 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE`
4993 @*/
4994 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc)
4995 {
4996   PetscInt Nf = dm->Nf;
4997 
4998   PetscFunctionBegin;
4999   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5000   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5001   PetscValidHeader(disc, 3);
5002   PetscCall(DMFieldEnlarge_Static(dm, Nf + 1));
5003   dm->fields[Nf].label = label;
5004   dm->fields[Nf].disc  = disc;
5005   PetscCall(PetscObjectReference((PetscObject)label));
5006   PetscCall(PetscObjectReference((PetscObject)disc));
5007   PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc));
5008   PetscCall(DMClearDS(dm));
5009   PetscFunctionReturn(PETSC_SUCCESS);
5010 }
5011 
5012 /*@
5013   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
5014 
5015   Logically Collective
5016 
5017   Input Parameters:
5018 + dm          - The `DM`
5019 . f           - The field index
5020 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells
5021 
5022   Level: intermediate
5023 
5024 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()`
5025 @*/
5026 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
5027 {
5028   PetscFunctionBegin;
5029   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);
5030   dm->fields[f].avoidTensor = avoidTensor;
5031   PetscFunctionReturn(PETSC_SUCCESS);
5032 }
5033 
5034 /*@
5035   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
5036 
5037   Not Collective
5038 
5039   Input Parameters:
5040 + dm - The `DM`
5041 - f  - The field index
5042 
5043   Output Parameter:
5044 . avoidTensor - The flag to avoid defining the field on tensor cells
5045 
5046   Level: intermediate
5047 
5048 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()`
5049 @*/
5050 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
5051 {
5052   PetscFunctionBegin;
5053   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);
5054   *avoidTensor = dm->fields[f].avoidTensor;
5055   PetscFunctionReturn(PETSC_SUCCESS);
5056 }
5057 
5058 /*@
5059   DMCopyFields - Copy the discretizations for the `DM` into another `DM`
5060 
5061   Collective
5062 
5063   Input Parameter:
5064 . dm - The `DM`
5065 
5066   Output Parameter:
5067 . newdm - The `DM`
5068 
5069   Level: advanced
5070 
5071 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()`
5072 @*/
5073 PetscErrorCode DMCopyFields(DM dm, DM newdm)
5074 {
5075   PetscInt Nf, f;
5076 
5077   PetscFunctionBegin;
5078   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
5079   PetscCall(DMGetNumFields(dm, &Nf));
5080   PetscCall(DMClearFields(newdm));
5081   for (f = 0; f < Nf; ++f) {
5082     DMLabel     label;
5083     PetscObject field;
5084     PetscBool   useCone, useClosure;
5085 
5086     PetscCall(DMGetField(dm, f, &label, &field));
5087     PetscCall(DMSetField(newdm, f, label, field));
5088     PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure));
5089     PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure));
5090   }
5091   PetscFunctionReturn(PETSC_SUCCESS);
5092 }
5093 
5094 /*@
5095   DMGetAdjacency - Returns the flags for determining variable influence
5096 
5097   Not Collective
5098 
5099   Input Parameters:
5100 + dm - The `DM` object
5101 - f  - The field number, or `PETSC_DEFAULT` for the default adjacency
5102 
5103   Output Parameters:
5104 + useCone    - Flag for variable influence starting with the cone operation
5105 - useClosure - Flag for variable influence using transitive closure
5106 
5107   Level: developer
5108 
5109   Notes:
5110 .vb
5111      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5112      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5113      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5114 .ve
5115   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5116 
5117 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()`
5118 @*/
5119 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
5120 {
5121   PetscFunctionBegin;
5122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5123   if (useCone) PetscAssertPointer(useCone, 3);
5124   if (useClosure) PetscAssertPointer(useClosure, 4);
5125   if (f < 0) {
5126     if (useCone) *useCone = dm->adjacency[0];
5127     if (useClosure) *useClosure = dm->adjacency[1];
5128   } else {
5129     PetscInt Nf;
5130 
5131     PetscCall(DMGetNumFields(dm, &Nf));
5132     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5133     if (useCone) *useCone = dm->fields[f].adjacency[0];
5134     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
5135   }
5136   PetscFunctionReturn(PETSC_SUCCESS);
5137 }
5138 
5139 /*@
5140   DMSetAdjacency - Set the flags for determining variable influence
5141 
5142   Not Collective
5143 
5144   Input Parameters:
5145 + dm         - The `DM` object
5146 . f          - The field number
5147 . useCone    - Flag for variable influence starting with the cone operation
5148 - useClosure - Flag for variable influence using transitive closure
5149 
5150   Level: developer
5151 
5152   Notes:
5153 .vb
5154      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5155      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5156      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5157 .ve
5158   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
5159 
5160 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()`
5161 @*/
5162 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
5163 {
5164   PetscFunctionBegin;
5165   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5166   if (f < 0) {
5167     dm->adjacency[0] = useCone;
5168     dm->adjacency[1] = useClosure;
5169   } else {
5170     PetscInt Nf;
5171 
5172     PetscCall(DMGetNumFields(dm, &Nf));
5173     PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf);
5174     dm->fields[f].adjacency[0] = useCone;
5175     dm->fields[f].adjacency[1] = useClosure;
5176   }
5177   PetscFunctionReturn(PETSC_SUCCESS);
5178 }
5179 
5180 /*@
5181   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
5182 
5183   Not collective
5184 
5185   Input Parameter:
5186 . dm - The `DM` object
5187 
5188   Output Parameters:
5189 + useCone    - Flag for variable influence starting with the cone operation
5190 - useClosure - Flag for variable influence using transitive closure
5191 
5192   Level: developer
5193 
5194   Notes:
5195 .vb
5196      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5197      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5198      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5199 .ve
5200 
5201 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5202 @*/
5203 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
5204 {
5205   PetscInt Nf;
5206 
5207   PetscFunctionBegin;
5208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5209   if (useCone) PetscAssertPointer(useCone, 2);
5210   if (useClosure) PetscAssertPointer(useClosure, 3);
5211   PetscCall(DMGetNumFields(dm, &Nf));
5212   if (!Nf) {
5213     PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5214   } else {
5215     PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure));
5216   }
5217   PetscFunctionReturn(PETSC_SUCCESS);
5218 }
5219 
5220 /*@
5221   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
5222 
5223   Not Collective
5224 
5225   Input Parameters:
5226 + dm         - The `DM` object
5227 . useCone    - Flag for variable influence starting with the cone operation
5228 - useClosure - Flag for variable influence using transitive closure
5229 
5230   Level: developer
5231 
5232   Notes:
5233 .vb
5234      FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
5235      FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
5236      FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
5237 .ve
5238 
5239 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()`
5240 @*/
5241 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5242 {
5243   PetscInt Nf;
5244 
5245   PetscFunctionBegin;
5246   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5247   PetscCall(DMGetNumFields(dm, &Nf));
5248   if (!Nf) {
5249     PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure));
5250   } else {
5251     PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure));
5252   }
5253   PetscFunctionReturn(PETSC_SUCCESS);
5254 }
5255 
5256 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5257 {
5258   DM           plex;
5259   DMLabel     *labels, *glabels;
5260   const char **names;
5261   char        *sendNames, *recvNames;
5262   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5263   size_t       len;
5264   MPI_Comm     comm;
5265   PetscMPIInt  rank, size, p, *counts, *displs;
5266 
5267   PetscFunctionBegin;
5268   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5269   PetscCallMPI(MPI_Comm_size(comm, &size));
5270   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5271   PetscCall(DMGetNumDS(dm, &Nds));
5272   for (s = 0; s < Nds; ++s) {
5273     PetscDS  dsBC;
5274     PetscInt numBd;
5275 
5276     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5277     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5278     maxLabels += numBd;
5279   }
5280   PetscCall(PetscCalloc1(maxLabels, &labels));
5281   /* Get list of labels to be completed */
5282   for (s = 0; s < Nds; ++s) {
5283     PetscDS  dsBC;
5284     PetscInt numBd, bd;
5285 
5286     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL));
5287     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5288     for (bd = 0; bd < numBd; ++bd) {
5289       DMLabel      label;
5290       PetscInt     field;
5291       PetscObject  obj;
5292       PetscClassId id;
5293 
5294       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5295       PetscCall(DMGetField(dm, field, NULL, &obj));
5296       PetscCall(PetscObjectGetClassId(obj, &id));
5297       if (!(id == PETSCFE_CLASSID) || !label) continue;
5298       for (l = 0; l < Nl; ++l)
5299         if (labels[l] == label) break;
5300       if (l == Nl) labels[Nl++] = label;
5301     }
5302   }
5303   /* Get label names */
5304   PetscCall(PetscMalloc1(Nl, &names));
5305   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l]));
5306   for (l = 0; l < Nl; ++l) {
5307     PetscCall(PetscStrlen(names[l], &len));
5308     maxLen = PetscMax(maxLen, (PetscInt)len + 2);
5309   }
5310   PetscCall(PetscFree(labels));
5311   PetscCall(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5312   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5313   for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen));
5314   PetscCall(PetscFree(names));
5315   /* Put all names on all processes */
5316   PetscCall(PetscCalloc2(size, &counts, size + 1, &displs));
5317   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5318   for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p];
5319   gNl = displs[size];
5320   for (p = 0; p < size; ++p) {
5321     counts[p] *= gmaxLen;
5322     displs[p] *= gmaxLen;
5323   }
5324   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5325   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5326   PetscCall(PetscFree2(counts, displs));
5327   PetscCall(PetscFree(sendNames));
5328   for (l = 0, gl = 0; l < gNl; ++l) {
5329     PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl]));
5330     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank);
5331     for (m = 0; m < gl; ++m)
5332       if (glabels[m] == glabels[gl]) continue;
5333     PetscCall(DMConvert(dm, DMPLEX, &plex));
5334     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5335     PetscCall(DMDestroy(&plex));
5336     ++gl;
5337   }
5338   PetscCall(PetscFree2(recvNames, glabels));
5339   PetscFunctionReturn(PETSC_SUCCESS);
5340 }
5341 
5342 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5343 {
5344   DMSpace *tmpd;
5345   PetscInt Nds = dm->Nds, s;
5346 
5347   PetscFunctionBegin;
5348   if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS);
5349   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5350   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5351   for (s = Nds; s < NdsNew; ++s) {
5352     tmpd[s].ds     = NULL;
5353     tmpd[s].label  = NULL;
5354     tmpd[s].fields = NULL;
5355   }
5356   PetscCall(PetscFree(dm->probs));
5357   dm->Nds   = NdsNew;
5358   dm->probs = tmpd;
5359   PetscFunctionReturn(PETSC_SUCCESS);
5360 }
5361 
5362 /*@
5363   DMGetNumDS - Get the number of discrete systems in the `DM`
5364 
5365   Not Collective
5366 
5367   Input Parameter:
5368 . dm - The `DM`
5369 
5370   Output Parameter:
5371 . Nds - The number of `PetscDS` objects
5372 
5373   Level: intermediate
5374 
5375 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()`
5376 @*/
5377 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5378 {
5379   PetscFunctionBegin;
5380   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5381   PetscAssertPointer(Nds, 2);
5382   *Nds = dm->Nds;
5383   PetscFunctionReturn(PETSC_SUCCESS);
5384 }
5385 
5386 /*@
5387   DMClearDS - Remove all discrete systems from the `DM`
5388 
5389   Logically Collective
5390 
5391   Input Parameter:
5392 . dm - The `DM`
5393 
5394   Level: intermediate
5395 
5396 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5397 @*/
5398 PetscErrorCode DMClearDS(DM dm)
5399 {
5400   PetscInt s;
5401 
5402   PetscFunctionBegin;
5403   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5404   for (s = 0; s < dm->Nds; ++s) {
5405     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5406     PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5407     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5408     PetscCall(ISDestroy(&dm->probs[s].fields));
5409   }
5410   PetscCall(PetscFree(dm->probs));
5411   dm->probs = NULL;
5412   dm->Nds   = 0;
5413   PetscFunctionReturn(PETSC_SUCCESS);
5414 }
5415 
5416 /*@
5417   DMGetDS - Get the default `PetscDS`
5418 
5419   Not Collective
5420 
5421   Input Parameter:
5422 . dm - The `DM`
5423 
5424   Output Parameter:
5425 . ds - The default `PetscDS`
5426 
5427   Level: intermediate
5428 
5429 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()`
5430 @*/
5431 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5432 {
5433   PetscFunctionBeginHot;
5434   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5435   PetscAssertPointer(ds, 2);
5436   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5437   *ds = dm->probs[0].ds;
5438   PetscFunctionReturn(PETSC_SUCCESS);
5439 }
5440 
5441 /*@
5442   DMGetCellDS - Get the `PetscDS` defined on a given cell
5443 
5444   Not Collective
5445 
5446   Input Parameters:
5447 + dm    - The `DM`
5448 - point - Cell for the `PetscDS`
5449 
5450   Output Parameters:
5451 + ds   - The `PetscDS` defined on the given cell
5452 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds
5453 
5454   Level: developer
5455 
5456 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()`
5457 @*/
5458 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5459 {
5460   PetscDS  dsDef = NULL;
5461   PetscInt s;
5462 
5463   PetscFunctionBeginHot;
5464   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5465   if (ds) PetscAssertPointer(ds, 3);
5466   if (dsIn) PetscAssertPointer(dsIn, 4);
5467   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5468   if (ds) *ds = NULL;
5469   if (dsIn) *dsIn = NULL;
5470   for (s = 0; s < dm->Nds; ++s) {
5471     PetscInt val;
5472 
5473     if (!dm->probs[s].label) {
5474       dsDef = dm->probs[s].ds;
5475     } else {
5476       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5477       if (val >= 0) {
5478         if (ds) *ds = dm->probs[s].ds;
5479         if (dsIn) *dsIn = dm->probs[s].dsIn;
5480         break;
5481       }
5482     }
5483   }
5484   if (ds && !*ds) *ds = dsDef;
5485   PetscFunctionReturn(PETSC_SUCCESS);
5486 }
5487 
5488 /*@
5489   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5490 
5491   Not Collective
5492 
5493   Input Parameters:
5494 + dm    - The `DM`
5495 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5496 
5497   Output Parameters:
5498 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5499 . ds     - The `PetscDS` defined on the given region, or `NULL`
5500 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5501 
5502   Level: advanced
5503 
5504   Note:
5505   If a non-`NULL` label is given, but there is no `PetscDS` on that specific label,
5506   the `PetscDS` for the full domain (if present) is returned. Returns with
5507   fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain.
5508 
5509 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5510 @*/
5511 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5512 {
5513   PetscInt Nds = dm->Nds, s;
5514 
5515   PetscFunctionBegin;
5516   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5517   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5518   if (fields) {
5519     PetscAssertPointer(fields, 3);
5520     *fields = NULL;
5521   }
5522   if (ds) {
5523     PetscAssertPointer(ds, 4);
5524     *ds = NULL;
5525   }
5526   if (dsIn) {
5527     PetscAssertPointer(dsIn, 5);
5528     *dsIn = NULL;
5529   }
5530   for (s = 0; s < Nds; ++s) {
5531     if (dm->probs[s].label == label || !dm->probs[s].label) {
5532       if (fields) *fields = dm->probs[s].fields;
5533       if (ds) *ds = dm->probs[s].ds;
5534       if (dsIn) *dsIn = dm->probs[s].dsIn;
5535       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5536     }
5537   }
5538   PetscFunctionReturn(PETSC_SUCCESS);
5539 }
5540 
5541 /*@
5542   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5543 
5544   Collective
5545 
5546   Input Parameters:
5547 + dm     - The `DM`
5548 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5549 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5550 . ds     - The `PetscDS` defined on the given region
5551 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5552 
5553   Level: advanced
5554 
5555   Note:
5556   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5557   the fields argument is ignored.
5558 
5559 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5560 @*/
5561 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5562 {
5563   PetscInt Nds = dm->Nds, s;
5564 
5565   PetscFunctionBegin;
5566   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5567   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5568   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5569   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5570   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5571   for (s = 0; s < Nds; ++s) {
5572     if (dm->probs[s].label == label) {
5573       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5574       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5575       dm->probs[s].ds   = ds;
5576       dm->probs[s].dsIn = dsIn;
5577       PetscFunctionReturn(PETSC_SUCCESS);
5578     }
5579   }
5580   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5581   PetscCall(PetscObjectReference((PetscObject)label));
5582   PetscCall(PetscObjectReference((PetscObject)fields));
5583   PetscCall(PetscObjectReference((PetscObject)ds));
5584   PetscCall(PetscObjectReference((PetscObject)dsIn));
5585   if (!label) {
5586     /* Put the NULL label at the front, so it is returned as the default */
5587     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5588     Nds = 0;
5589   }
5590   dm->probs[Nds].label  = label;
5591   dm->probs[Nds].fields = fields;
5592   dm->probs[Nds].ds     = ds;
5593   dm->probs[Nds].dsIn   = dsIn;
5594   PetscFunctionReturn(PETSC_SUCCESS);
5595 }
5596 
5597 /*@
5598   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5599 
5600   Not Collective
5601 
5602   Input Parameters:
5603 + dm  - The `DM`
5604 - num - The region number, in [0, Nds)
5605 
5606   Output Parameters:
5607 + label  - The region label, or `NULL`
5608 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5609 . ds     - The `PetscDS` defined on the given region, or `NULL`
5610 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5611 
5612   Level: advanced
5613 
5614 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5615 @*/
5616 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5617 {
5618   PetscInt Nds;
5619 
5620   PetscFunctionBegin;
5621   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5622   PetscCall(DMGetNumDS(dm, &Nds));
5623   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5624   if (label) {
5625     PetscAssertPointer(label, 3);
5626     *label = dm->probs[num].label;
5627   }
5628   if (fields) {
5629     PetscAssertPointer(fields, 4);
5630     *fields = dm->probs[num].fields;
5631   }
5632   if (ds) {
5633     PetscAssertPointer(ds, 5);
5634     *ds = dm->probs[num].ds;
5635   }
5636   if (dsIn) {
5637     PetscAssertPointer(dsIn, 6);
5638     *dsIn = dm->probs[num].dsIn;
5639   }
5640   PetscFunctionReturn(PETSC_SUCCESS);
5641 }
5642 
5643 /*@
5644   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5645 
5646   Not Collective
5647 
5648   Input Parameters:
5649 + dm     - The `DM`
5650 . num    - The region number, in [0, Nds)
5651 . label  - The region label, or `NULL`
5652 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5653 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5654 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5655 
5656   Level: advanced
5657 
5658 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5659 @*/
5660 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5661 {
5662   PetscInt Nds;
5663 
5664   PetscFunctionBegin;
5665   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5666   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5667   PetscCall(DMGetNumDS(dm, &Nds));
5668   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5669   PetscCall(PetscObjectReference((PetscObject)label));
5670   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5671   dm->probs[num].label = label;
5672   if (fields) {
5673     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5674     PetscCall(PetscObjectReference((PetscObject)fields));
5675     PetscCall(ISDestroy(&dm->probs[num].fields));
5676     dm->probs[num].fields = fields;
5677   }
5678   if (ds) {
5679     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5680     PetscCall(PetscObjectReference((PetscObject)ds));
5681     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5682     dm->probs[num].ds = ds;
5683   }
5684   if (dsIn) {
5685     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5686     PetscCall(PetscObjectReference((PetscObject)dsIn));
5687     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5688     dm->probs[num].dsIn = dsIn;
5689   }
5690   PetscFunctionReturn(PETSC_SUCCESS);
5691 }
5692 
5693 /*@
5694   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5695 
5696   Not Collective
5697 
5698   Input Parameters:
5699 + dm - The `DM`
5700 - ds - The `PetscDS` defined on the given region
5701 
5702   Output Parameter:
5703 . num - The region number, in [0, Nds), or -1 if not found
5704 
5705   Level: advanced
5706 
5707 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5708 @*/
5709 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5710 {
5711   PetscInt Nds, n;
5712 
5713   PetscFunctionBegin;
5714   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5715   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5716   PetscAssertPointer(num, 3);
5717   PetscCall(DMGetNumDS(dm, &Nds));
5718   for (n = 0; n < Nds; ++n)
5719     if (ds == dm->probs[n].ds) break;
5720   if (n >= Nds) *num = -1;
5721   else *num = n;
5722   PetscFunctionReturn(PETSC_SUCCESS);
5723 }
5724 
5725 /*@C
5726   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5727 
5728   Not Collective
5729 
5730   Input Parameters:
5731 + dm     - The `DM`
5732 . Nc     - The number of components for the field
5733 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5734 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5735 
5736   Output Parameter:
5737 . fem - The `PetscFE`
5738 
5739   Level: intermediate
5740 
5741   Note:
5742   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5743 
5744 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5745 @*/
5746 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5747 {
5748   DMPolytopeType ct;
5749   PetscInt       dim, cStart;
5750 
5751   PetscFunctionBegin;
5752   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5753   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5754   if (prefix) PetscAssertPointer(prefix, 3);
5755   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5756   PetscAssertPointer(fem, 5);
5757   PetscCall(DMGetDimension(dm, &dim));
5758   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5759   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5760   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5761   PetscFunctionReturn(PETSC_SUCCESS);
5762 }
5763 
5764 /*@
5765   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5766 
5767   Collective
5768 
5769   Input Parameter:
5770 . dm - The `DM`
5771 
5772   Options Database Key:
5773 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5774 
5775   Level: intermediate
5776 
5777 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5778 @*/
5779 PetscErrorCode DMCreateDS(DM dm)
5780 {
5781   MPI_Comm  comm;
5782   PetscDS   dsDef;
5783   DMLabel  *labelSet;
5784   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5785   PetscBool doSetup = PETSC_TRUE, flg;
5786 
5787   PetscFunctionBegin;
5788   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5789   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5790   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5791   PetscCall(DMGetCoordinateDim(dm, &dE));
5792   /* Determine how many regions we have */
5793   PetscCall(PetscMalloc1(Nf, &labelSet));
5794   Nl   = 0;
5795   Ndef = 0;
5796   for (f = 0; f < Nf; ++f) {
5797     DMLabel  label = dm->fields[f].label;
5798     PetscInt l;
5799 
5800 #ifdef PETSC_HAVE_LIBCEED
5801     /* Move CEED context to discretizations */
5802     {
5803       PetscClassId id;
5804 
5805       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5806       if (id == PETSCFE_CLASSID) {
5807         Ceed ceed;
5808 
5809         PetscCall(DMGetCeed(dm, &ceed));
5810         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5811       }
5812     }
5813 #endif
5814     if (!label) {
5815       ++Ndef;
5816       continue;
5817     }
5818     for (l = 0; l < Nl; ++l)
5819       if (label == labelSet[l]) break;
5820     if (l < Nl) continue;
5821     labelSet[Nl++] = label;
5822   }
5823   /* Create default DS if there are no labels to intersect with */
5824   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5825   if (!dsDef && Ndef && !Nl) {
5826     IS        fields;
5827     PetscInt *fld, nf;
5828 
5829     for (f = 0, nf = 0; f < Nf; ++f)
5830       if (!dm->fields[f].label) ++nf;
5831     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5832     PetscCall(PetscMalloc1(nf, &fld));
5833     for (f = 0, nf = 0; f < Nf; ++f)
5834       if (!dm->fields[f].label) fld[nf++] = f;
5835     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5836     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5837     PetscCall(ISSetType(fields, ISGENERAL));
5838     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5839 
5840     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5841     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5842     PetscCall(PetscDSDestroy(&dsDef));
5843     PetscCall(ISDestroy(&fields));
5844   }
5845   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5846   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5847   /* Intersect labels with default fields */
5848   if (Ndef && Nl) {
5849     DM              plex;
5850     DMLabel         cellLabel;
5851     IS              fieldIS, allcellIS, defcellIS = NULL;
5852     PetscInt       *fields;
5853     const PetscInt *cells;
5854     PetscInt        depth, nf = 0, n, c;
5855 
5856     PetscCall(DMConvert(dm, DMPLEX, &plex));
5857     PetscCall(DMPlexGetDepth(plex, &depth));
5858     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5859     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5860     /* TODO This looks like it only works for one label */
5861     for (l = 0; l < Nl; ++l) {
5862       DMLabel label = labelSet[l];
5863       IS      pointIS;
5864 
5865       PetscCall(ISDestroy(&defcellIS));
5866       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5867       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5868       PetscCall(ISDestroy(&pointIS));
5869     }
5870     PetscCall(ISDestroy(&allcellIS));
5871 
5872     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5873     PetscCall(ISGetLocalSize(defcellIS, &n));
5874     PetscCall(ISGetIndices(defcellIS, &cells));
5875     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5876     PetscCall(ISRestoreIndices(defcellIS, &cells));
5877     PetscCall(ISDestroy(&defcellIS));
5878     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5879 
5880     PetscCall(PetscMalloc1(Ndef, &fields));
5881     for (f = 0; f < Nf; ++f)
5882       if (!dm->fields[f].label) fields[nf++] = f;
5883     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
5884     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
5885     PetscCall(ISSetType(fieldIS, ISGENERAL));
5886     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
5887 
5888     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5889     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
5890     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5891     PetscCall(DMLabelDestroy(&cellLabel));
5892     PetscCall(PetscDSDestroy(&dsDef));
5893     PetscCall(ISDestroy(&fieldIS));
5894     PetscCall(DMDestroy(&plex));
5895   }
5896   /* Create label DSes
5897      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5898   */
5899   /* TODO Should check that labels are disjoint */
5900   for (l = 0; l < Nl; ++l) {
5901     DMLabel   label = labelSet[l];
5902     PetscDS   ds, dsIn = NULL;
5903     IS        fields;
5904     PetscInt *fld, nf;
5905 
5906     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
5907     for (f = 0, nf = 0; f < Nf; ++f)
5908       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5909     PetscCall(PetscMalloc1(nf, &fld));
5910     for (f = 0, nf = 0; f < Nf; ++f)
5911       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5912     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5913     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5914     PetscCall(ISSetType(fields, ISGENERAL));
5915     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5916     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
5917     {
5918       DMPolytopeType ct;
5919       PetscInt       lStart, lEnd;
5920       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
5921 
5922       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
5923       if (lStart >= 0) {
5924         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
5925         switch (ct) {
5926         case DM_POLYTOPE_POINT_PRISM_TENSOR:
5927         case DM_POLYTOPE_SEG_PRISM_TENSOR:
5928         case DM_POLYTOPE_TRI_PRISM_TENSOR:
5929         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5930           isCohesiveLocal = PETSC_TRUE;
5931           break;
5932         default:
5933           break;
5934         }
5935       }
5936       PetscCall(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
5937       if (isCohesive) {
5938         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
5939         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
5940       }
5941       for (f = 0, nf = 0; f < Nf; ++f) {
5942         if (label == dm->fields[f].label || !dm->fields[f].label) {
5943           if (label == dm->fields[f].label) {
5944             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
5945             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
5946             if (dsIn) {
5947               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
5948               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
5949             }
5950           }
5951           ++nf;
5952         }
5953       }
5954     }
5955     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
5956     PetscCall(ISDestroy(&fields));
5957     PetscCall(PetscDSDestroy(&ds));
5958     PetscCall(PetscDSDestroy(&dsIn));
5959   }
5960   PetscCall(PetscFree(labelSet));
5961   /* Set fields in DSes */
5962   for (s = 0; s < dm->Nds; ++s) {
5963     PetscDS         ds     = dm->probs[s].ds;
5964     PetscDS         dsIn   = dm->probs[s].dsIn;
5965     IS              fields = dm->probs[s].fields;
5966     const PetscInt *fld;
5967     PetscInt        nf, dsnf;
5968     PetscBool       isCohesive;
5969 
5970     PetscCall(PetscDSGetNumFields(ds, &dsnf));
5971     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
5972     PetscCall(ISGetLocalSize(fields, &nf));
5973     PetscCall(ISGetIndices(fields, &fld));
5974     for (f = 0; f < nf; ++f) {
5975       PetscObject  disc = dm->fields[fld[f]].disc;
5976       PetscBool    isCohesiveField;
5977       PetscClassId id;
5978 
5979       /* Handle DS with no fields */
5980       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
5981       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5982       if (isCohesive) {
5983         if (!isCohesiveField) {
5984           PetscObject bdDisc;
5985 
5986           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
5987           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
5988           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
5989         } else {
5990           PetscCall(PetscDSSetDiscretization(ds, f, disc));
5991           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
5992         }
5993       } else {
5994         PetscCall(PetscDSSetDiscretization(ds, f, disc));
5995       }
5996       /* We allow people to have placeholder fields and construct the Section by hand */
5997       PetscCall(PetscObjectGetClassId(disc, &id));
5998       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5999     }
6000     PetscCall(ISRestoreIndices(fields, &fld));
6001   }
6002   /* Allow k-jet tabulation */
6003   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
6004   if (flg) {
6005     for (s = 0; s < dm->Nds; ++s) {
6006       PetscDS  ds   = dm->probs[s].ds;
6007       PetscDS  dsIn = dm->probs[s].dsIn;
6008       PetscInt Nf, f;
6009 
6010       PetscCall(PetscDSGetNumFields(ds, &Nf));
6011       for (f = 0; f < Nf; ++f) {
6012         PetscCall(PetscDSSetJetDegree(ds, f, k));
6013         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6014       }
6015     }
6016   }
6017   /* Setup DSes */
6018   if (doSetup) {
6019     for (s = 0; s < dm->Nds; ++s) {
6020       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6021       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6022     }
6023   }
6024   PetscFunctionReturn(PETSC_SUCCESS);
6025 }
6026 
6027 /*@
6028   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6029 
6030   Collective
6031 
6032   Input Parameters:
6033 + dm   - The `DM`
6034 - time - The time
6035 
6036   Output Parameters:
6037 + u   - The vector will be filled with exact solution values, or `NULL`
6038 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL`
6039 
6040   Level: developer
6041 
6042   Note:
6043   The user must call `PetscDSSetExactSolution()` before using this routine
6044 
6045 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()`
6046 @*/
6047 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6048 {
6049   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6050   void   **ectxs;
6051   Vec      locu, locu_t;
6052   PetscInt Nf, Nds, s;
6053 
6054   PetscFunctionBegin;
6055   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6056   if (u) {
6057     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6058     PetscCall(DMGetLocalVector(dm, &locu));
6059     PetscCall(VecSet(locu, 0.));
6060   }
6061   if (u_t) {
6062     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6063     PetscCall(DMGetLocalVector(dm, &locu_t));
6064     PetscCall(VecSet(locu_t, 0.));
6065   }
6066   PetscCall(DMGetNumFields(dm, &Nf));
6067   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6068   PetscCall(DMGetNumDS(dm, &Nds));
6069   for (s = 0; s < Nds; ++s) {
6070     PetscDS         ds;
6071     DMLabel         label;
6072     IS              fieldIS;
6073     const PetscInt *fields, id = 1;
6074     PetscInt        dsNf, f;
6075 
6076     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6077     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6078     PetscCall(ISGetIndices(fieldIS, &fields));
6079     PetscCall(PetscArrayzero(exacts, Nf));
6080     PetscCall(PetscArrayzero(ectxs, Nf));
6081     if (u) {
6082       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6083       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6084       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6085     }
6086     if (u_t) {
6087       PetscCall(PetscArrayzero(exacts, Nf));
6088       PetscCall(PetscArrayzero(ectxs, Nf));
6089       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6090       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6091       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6092     }
6093     PetscCall(ISRestoreIndices(fieldIS, &fields));
6094   }
6095   if (u) {
6096     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6097     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6098   }
6099   if (u_t) {
6100     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6101     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6102   }
6103   PetscCall(PetscFree2(exacts, ectxs));
6104   if (u) {
6105     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6106     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6107     PetscCall(DMRestoreLocalVector(dm, &locu));
6108   }
6109   if (u_t) {
6110     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6111     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6112     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6113   }
6114   PetscFunctionReturn(PETSC_SUCCESS);
6115 }
6116 
6117 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
6118 {
6119   PetscDS dsNew, dsInNew = NULL;
6120 
6121   PetscFunctionBegin;
6122   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6123   PetscCall(PetscDSCopy(ds, dm, dsNew));
6124   if (dsIn) {
6125     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6126     PetscCall(PetscDSCopy(dsIn, dm, dsInNew));
6127   }
6128   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6129   PetscCall(PetscDSDestroy(&dsNew));
6130   PetscCall(PetscDSDestroy(&dsInNew));
6131   PetscFunctionReturn(PETSC_SUCCESS);
6132 }
6133 
6134 /*@
6135   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6136 
6137   Collective
6138 
6139   Input Parameter:
6140 . dm - The `DM`
6141 
6142   Output Parameter:
6143 . newdm - The `DM`
6144 
6145   Level: advanced
6146 
6147 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6148 @*/
6149 PetscErrorCode DMCopyDS(DM dm, DM newdm)
6150 {
6151   PetscInt Nds, s;
6152 
6153   PetscFunctionBegin;
6154   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6155   PetscCall(DMGetNumDS(dm, &Nds));
6156   PetscCall(DMClearDS(newdm));
6157   for (s = 0; s < Nds; ++s) {
6158     DMLabel  label;
6159     IS       fields;
6160     PetscDS  ds, dsIn, newds;
6161     PetscInt Nbd, bd;
6162 
6163     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6164     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6165     PetscCall(DMTransferDS_Internal(newdm, label, fields, ds, dsIn));
6166     /* Complete new labels in the new DS */
6167     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6168     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6169     for (bd = 0; bd < Nbd; ++bd) {
6170       PetscWeakForm wf;
6171       DMLabel       label;
6172       PetscInt      field;
6173 
6174       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6175       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6176     }
6177   }
6178   PetscCall(DMCompleteBCLabels_Internal(newdm));
6179   PetscFunctionReturn(PETSC_SUCCESS);
6180 }
6181 
6182 /*@
6183   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6184 
6185   Collective
6186 
6187   Input Parameter:
6188 . dm - The `DM`
6189 
6190   Output Parameter:
6191 . newdm - The `DM`
6192 
6193   Level: advanced
6194 
6195   Developer Notes:
6196   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6197 
6198 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()`
6199 @*/
6200 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6201 {
6202   PetscFunctionBegin;
6203   PetscCall(DMCopyFields(dm, newdm));
6204   PetscCall(DMCopyDS(dm, newdm));
6205   PetscFunctionReturn(PETSC_SUCCESS);
6206 }
6207 
6208 /*@
6209   DMGetDimension - Return the topological dimension of the `DM`
6210 
6211   Not Collective
6212 
6213   Input Parameter:
6214 . dm - The `DM`
6215 
6216   Output Parameter:
6217 . dim - The topological dimension
6218 
6219   Level: beginner
6220 
6221 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()`
6222 @*/
6223 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6224 {
6225   PetscFunctionBegin;
6226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6227   PetscAssertPointer(dim, 2);
6228   *dim = dm->dim;
6229   PetscFunctionReturn(PETSC_SUCCESS);
6230 }
6231 
6232 /*@
6233   DMSetDimension - Set the topological dimension of the `DM`
6234 
6235   Collective
6236 
6237   Input Parameters:
6238 + dm  - The `DM`
6239 - dim - The topological dimension
6240 
6241   Level: beginner
6242 
6243 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()`
6244 @*/
6245 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6246 {
6247   PetscDS  ds;
6248   PetscInt Nds, n;
6249 
6250   PetscFunctionBegin;
6251   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6252   PetscValidLogicalCollectiveInt(dm, dim, 2);
6253   dm->dim = dim;
6254   if (dm->dim >= 0) {
6255     PetscCall(DMGetNumDS(dm, &Nds));
6256     for (n = 0; n < Nds; ++n) {
6257       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6258       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6259     }
6260   }
6261   PetscFunctionReturn(PETSC_SUCCESS);
6262 }
6263 
6264 /*@
6265   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6266 
6267   Collective
6268 
6269   Input Parameters:
6270 + dm  - the `DM`
6271 - dim - the dimension
6272 
6273   Output Parameters:
6274 + pStart - The first point of the given dimension
6275 - pEnd   - The first point following points of the given dimension
6276 
6277   Level: intermediate
6278 
6279   Note:
6280   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6281   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6282   then the interval is empty.
6283 
6284 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6285 @*/
6286 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6287 {
6288   PetscInt d;
6289 
6290   PetscFunctionBegin;
6291   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6292   PetscCall(DMGetDimension(dm, &d));
6293   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6294   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6295   PetscFunctionReturn(PETSC_SUCCESS);
6296 }
6297 
6298 /*@
6299   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6300 
6301   Collective
6302 
6303   Input Parameter:
6304 . dm - The original `DM`
6305 
6306   Output Parameter:
6307 . odm - The `DM` which provides the layout for output
6308 
6309   Level: intermediate
6310 
6311   Note:
6312   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6313   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6314   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6315 
6316 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6317 @*/
6318 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6319 {
6320   PetscSection section;
6321   PetscBool    hasConstraints, ghasConstraints;
6322 
6323   PetscFunctionBegin;
6324   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6325   PetscAssertPointer(odm, 2);
6326   PetscCall(DMGetLocalSection(dm, &section));
6327   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6328   PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6329   if (!ghasConstraints) {
6330     *odm = dm;
6331     PetscFunctionReturn(PETSC_SUCCESS);
6332   }
6333   if (!dm->dmBC) {
6334     PetscSection newSection, gsection;
6335     PetscSF      sf;
6336 
6337     PetscCall(DMClone(dm, &dm->dmBC));
6338     PetscCall(DMCopyDisc(dm, dm->dmBC));
6339     PetscCall(PetscSectionClone(section, &newSection));
6340     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6341     PetscCall(PetscSectionDestroy(&newSection));
6342     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6343     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
6344     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6345     PetscCall(PetscSectionDestroy(&gsection));
6346   }
6347   *odm = dm->dmBC;
6348   PetscFunctionReturn(PETSC_SUCCESS);
6349 }
6350 
6351 /*@
6352   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6353 
6354   Input Parameter:
6355 . dm - The original `DM`
6356 
6357   Output Parameters:
6358 + num - The output sequence number
6359 - val - The output sequence value
6360 
6361   Level: intermediate
6362 
6363   Note:
6364   This is intended for output that should appear in sequence, for instance
6365   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6366 
6367   Developer Notes:
6368   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6369   not directly related to the `DM`.
6370 
6371 .seealso: [](ch_dmbase), `DM`, `VecView()`
6372 @*/
6373 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6374 {
6375   PetscFunctionBegin;
6376   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6377   if (num) {
6378     PetscAssertPointer(num, 2);
6379     *num = dm->outputSequenceNum;
6380   }
6381   if (val) {
6382     PetscAssertPointer(val, 3);
6383     *val = dm->outputSequenceVal;
6384   }
6385   PetscFunctionReturn(PETSC_SUCCESS);
6386 }
6387 
6388 /*@
6389   DMSetOutputSequenceNumber - Set the sequence number/value for output
6390 
6391   Input Parameters:
6392 + dm  - The original `DM`
6393 . num - The output sequence number
6394 - val - The output sequence value
6395 
6396   Level: intermediate
6397 
6398   Note:
6399   This is intended for output that should appear in sequence, for instance
6400   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6401 
6402 .seealso: [](ch_dmbase), `DM`, `VecView()`
6403 @*/
6404 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6405 {
6406   PetscFunctionBegin;
6407   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6408   dm->outputSequenceNum = num;
6409   dm->outputSequenceVal = val;
6410   PetscFunctionReturn(PETSC_SUCCESS);
6411 }
6412 
6413 /*@C
6414   DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6415 
6416   Input Parameters:
6417 + dm     - The original `DM`
6418 . viewer - The viewer to get it from
6419 . name   - The sequence name
6420 - num    - The output sequence number
6421 
6422   Output Parameter:
6423 . val - The output sequence value
6424 
6425   Level: intermediate
6426 
6427   Note:
6428   This is intended for output that should appear in sequence, for instance
6429   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6430 
6431   Developer Notes:
6432   It is unclear at the user API level why a `DM` is needed as input
6433 
6434 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6435 @*/
6436 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6437 {
6438   PetscBool ishdf5;
6439 
6440   PetscFunctionBegin;
6441   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6442   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6443   PetscAssertPointer(val, 5);
6444   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6445   if (ishdf5) {
6446 #if defined(PETSC_HAVE_HDF5)
6447     PetscScalar value;
6448 
6449     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6450     *val = PetscRealPart(value);
6451 #endif
6452   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6453   PetscFunctionReturn(PETSC_SUCCESS);
6454 }
6455 
6456 /*@
6457   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6458 
6459   Not Collective
6460 
6461   Input Parameter:
6462 . dm - The `DM`
6463 
6464   Output Parameter:
6465 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6466 
6467   Level: beginner
6468 
6469 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()`
6470 @*/
6471 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6472 {
6473   PetscFunctionBegin;
6474   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6475   PetscAssertPointer(useNatural, 2);
6476   *useNatural = dm->useNatural;
6477   PetscFunctionReturn(PETSC_SUCCESS);
6478 }
6479 
6480 /*@
6481   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6482 
6483   Collective
6484 
6485   Input Parameters:
6486 + dm         - The `DM`
6487 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6488 
6489   Note:
6490   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6491 
6492   Level: beginner
6493 
6494 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6495 @*/
6496 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6497 {
6498   PetscFunctionBegin;
6499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6500   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6501   dm->useNatural = useNatural;
6502   PetscFunctionReturn(PETSC_SUCCESS);
6503 }
6504 
6505 /*@C
6506   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6507 
6508   Not Collective
6509 
6510   Input Parameters:
6511 + dm   - The `DM` object
6512 - name - The label name
6513 
6514   Level: intermediate
6515 
6516 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6517 @*/
6518 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6519 {
6520   PetscBool flg;
6521   DMLabel   label;
6522 
6523   PetscFunctionBegin;
6524   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6525   PetscAssertPointer(name, 2);
6526   PetscCall(DMHasLabel(dm, name, &flg));
6527   if (!flg) {
6528     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6529     PetscCall(DMAddLabel(dm, label));
6530     PetscCall(DMLabelDestroy(&label));
6531   }
6532   PetscFunctionReturn(PETSC_SUCCESS);
6533 }
6534 
6535 /*@C
6536   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6537 
6538   Not Collective
6539 
6540   Input Parameters:
6541 + dm   - The `DM` object
6542 . l    - The index for the label
6543 - name - The label name
6544 
6545   Level: intermediate
6546 
6547 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6548 @*/
6549 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6550 {
6551   DMLabelLink orig, prev = NULL;
6552   DMLabel     label;
6553   PetscInt    Nl, m;
6554   PetscBool   flg, match;
6555   const char *lname;
6556 
6557   PetscFunctionBegin;
6558   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6559   PetscAssertPointer(name, 3);
6560   PetscCall(DMHasLabel(dm, name, &flg));
6561   if (!flg) {
6562     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6563     PetscCall(DMAddLabel(dm, label));
6564     PetscCall(DMLabelDestroy(&label));
6565   }
6566   PetscCall(DMGetNumLabels(dm, &Nl));
6567   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6568   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6569     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6570     PetscCall(PetscStrcmp(name, lname, &match));
6571     if (match) break;
6572   }
6573   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6574   if (!m) dm->labels = orig->next;
6575   else prev->next = orig->next;
6576   if (!l) {
6577     orig->next = dm->labels;
6578     dm->labels = orig;
6579   } else {
6580     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next)
6581       ;
6582     orig->next = prev->next;
6583     prev->next = orig;
6584   }
6585   PetscFunctionReturn(PETSC_SUCCESS);
6586 }
6587 
6588 /*@C
6589   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6590 
6591   Not Collective
6592 
6593   Input Parameters:
6594 + dm    - The `DM` object
6595 . name  - The label name
6596 - point - The mesh point
6597 
6598   Output Parameter:
6599 . value - The label value for this point, or -1 if the point is not in the label
6600 
6601   Level: beginner
6602 
6603 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6604 @*/
6605 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6606 {
6607   DMLabel label;
6608 
6609   PetscFunctionBegin;
6610   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6611   PetscAssertPointer(name, 2);
6612   PetscCall(DMGetLabel(dm, name, &label));
6613   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6614   PetscCall(DMLabelGetValue(label, point, value));
6615   PetscFunctionReturn(PETSC_SUCCESS);
6616 }
6617 
6618 /*@C
6619   DMSetLabelValue - Add a point to a `DMLabel` with given value
6620 
6621   Not Collective
6622 
6623   Input Parameters:
6624 + dm    - The `DM` object
6625 . name  - The label name
6626 . point - The mesh point
6627 - value - The label value for this point
6628 
6629   Output Parameter:
6630 
6631   Level: beginner
6632 
6633 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6634 @*/
6635 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6636 {
6637   DMLabel label;
6638 
6639   PetscFunctionBegin;
6640   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6641   PetscAssertPointer(name, 2);
6642   PetscCall(DMGetLabel(dm, name, &label));
6643   if (!label) {
6644     PetscCall(DMCreateLabel(dm, name));
6645     PetscCall(DMGetLabel(dm, name, &label));
6646   }
6647   PetscCall(DMLabelSetValue(label, point, value));
6648   PetscFunctionReturn(PETSC_SUCCESS);
6649 }
6650 
6651 /*@C
6652   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6653 
6654   Not Collective
6655 
6656   Input Parameters:
6657 + dm    - The `DM` object
6658 . name  - The label name
6659 . point - The mesh point
6660 - value - The label value for this point
6661 
6662   Level: beginner
6663 
6664 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6665 @*/
6666 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6667 {
6668   DMLabel label;
6669 
6670   PetscFunctionBegin;
6671   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6672   PetscAssertPointer(name, 2);
6673   PetscCall(DMGetLabel(dm, name, &label));
6674   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6675   PetscCall(DMLabelClearValue(label, point, value));
6676   PetscFunctionReturn(PETSC_SUCCESS);
6677 }
6678 
6679 /*@C
6680   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6681 
6682   Not Collective
6683 
6684   Input Parameters:
6685 + dm   - The `DM` object
6686 - name - The label name
6687 
6688   Output Parameter:
6689 . size - The number of different integer ids, or 0 if the label does not exist
6690 
6691   Level: beginner
6692 
6693   Developer Notes:
6694   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6695 
6696 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6697 @*/
6698 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6699 {
6700   DMLabel label;
6701 
6702   PetscFunctionBegin;
6703   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6704   PetscAssertPointer(name, 2);
6705   PetscAssertPointer(size, 3);
6706   PetscCall(DMGetLabel(dm, name, &label));
6707   *size = 0;
6708   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6709   PetscCall(DMLabelGetNumValues(label, size));
6710   PetscFunctionReturn(PETSC_SUCCESS);
6711 }
6712 
6713 /*@C
6714   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6715 
6716   Not Collective
6717 
6718   Input Parameters:
6719 + dm   - The `DM` object
6720 - name - The label name
6721 
6722   Output Parameter:
6723 . ids - The integer ids, or `NULL` if the label does not exist
6724 
6725   Level: beginner
6726 
6727 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()`
6728 @*/
6729 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6730 {
6731   DMLabel label;
6732 
6733   PetscFunctionBegin;
6734   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6735   PetscAssertPointer(name, 2);
6736   PetscAssertPointer(ids, 3);
6737   PetscCall(DMGetLabel(dm, name, &label));
6738   *ids = NULL;
6739   if (label) {
6740     PetscCall(DMLabelGetValueIS(label, ids));
6741   } else {
6742     /* returning an empty IS */
6743     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6744   }
6745   PetscFunctionReturn(PETSC_SUCCESS);
6746 }
6747 
6748 /*@C
6749   DMGetStratumSize - Get the number of points in a label stratum
6750 
6751   Not Collective
6752 
6753   Input Parameters:
6754 + dm    - The `DM` object
6755 . name  - The label name
6756 - value - The stratum value
6757 
6758   Output Parameter:
6759 . size - The number of points, also called the stratum size
6760 
6761   Level: beginner
6762 
6763 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6764 @*/
6765 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6766 {
6767   DMLabel label;
6768 
6769   PetscFunctionBegin;
6770   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6771   PetscAssertPointer(name, 2);
6772   PetscAssertPointer(size, 4);
6773   PetscCall(DMGetLabel(dm, name, &label));
6774   *size = 0;
6775   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6776   PetscCall(DMLabelGetStratumSize(label, value, size));
6777   PetscFunctionReturn(PETSC_SUCCESS);
6778 }
6779 
6780 /*@C
6781   DMGetStratumIS - Get the points in a label stratum
6782 
6783   Not Collective
6784 
6785   Input Parameters:
6786 + dm    - The `DM` object
6787 . name  - The label name
6788 - value - The stratum value
6789 
6790   Output Parameter:
6791 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
6792 
6793   Level: beginner
6794 
6795 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6796 @*/
6797 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6798 {
6799   DMLabel label;
6800 
6801   PetscFunctionBegin;
6802   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6803   PetscAssertPointer(name, 2);
6804   PetscAssertPointer(points, 4);
6805   PetscCall(DMGetLabel(dm, name, &label));
6806   *points = NULL;
6807   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6808   PetscCall(DMLabelGetStratumIS(label, value, points));
6809   PetscFunctionReturn(PETSC_SUCCESS);
6810 }
6811 
6812 /*@C
6813   DMSetStratumIS - Set the points in a label stratum
6814 
6815   Not Collective
6816 
6817   Input Parameters:
6818 + dm     - The `DM` object
6819 . name   - The label name
6820 . value  - The stratum value
6821 - points - The stratum points
6822 
6823   Level: beginner
6824 
6825 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
6826 @*/
6827 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6828 {
6829   DMLabel label;
6830 
6831   PetscFunctionBegin;
6832   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6833   PetscAssertPointer(name, 2);
6834   PetscValidHeaderSpecific(points, IS_CLASSID, 4);
6835   PetscCall(DMGetLabel(dm, name, &label));
6836   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6837   PetscCall(DMLabelSetStratumIS(label, value, points));
6838   PetscFunctionReturn(PETSC_SUCCESS);
6839 }
6840 
6841 /*@C
6842   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
6843 
6844   Not Collective
6845 
6846   Input Parameters:
6847 + dm    - The `DM` object
6848 . name  - The label name
6849 - value - The label value for this point
6850 
6851   Output Parameter:
6852 
6853   Level: beginner
6854 
6855 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6856 @*/
6857 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6858 {
6859   DMLabel label;
6860 
6861   PetscFunctionBegin;
6862   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6863   PetscAssertPointer(name, 2);
6864   PetscCall(DMGetLabel(dm, name, &label));
6865   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6866   PetscCall(DMLabelClearStratum(label, value));
6867   PetscFunctionReturn(PETSC_SUCCESS);
6868 }
6869 
6870 /*@
6871   DMGetNumLabels - Return the number of labels defined by on the `DM`
6872 
6873   Not Collective
6874 
6875   Input Parameter:
6876 . dm - The `DM` object
6877 
6878   Output Parameter:
6879 . numLabels - the number of Labels
6880 
6881   Level: intermediate
6882 
6883 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6884 @*/
6885 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6886 {
6887   DMLabelLink next = dm->labels;
6888   PetscInt    n    = 0;
6889 
6890   PetscFunctionBegin;
6891   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6892   PetscAssertPointer(numLabels, 2);
6893   while (next) {
6894     ++n;
6895     next = next->next;
6896   }
6897   *numLabels = n;
6898   PetscFunctionReturn(PETSC_SUCCESS);
6899 }
6900 
6901 /*@C
6902   DMGetLabelName - Return the name of nth label
6903 
6904   Not Collective
6905 
6906   Input Parameters:
6907 + dm - The `DM` object
6908 - n  - the label number
6909 
6910   Output Parameter:
6911 . name - the label name
6912 
6913   Level: intermediate
6914 
6915   Developer Notes:
6916   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
6917 
6918 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6919 @*/
6920 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6921 {
6922   DMLabelLink next = dm->labels;
6923   PetscInt    l    = 0;
6924 
6925   PetscFunctionBegin;
6926   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6927   PetscAssertPointer(name, 3);
6928   while (next) {
6929     if (l == n) {
6930       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
6931       PetscFunctionReturn(PETSC_SUCCESS);
6932     }
6933     ++l;
6934     next = next->next;
6935   }
6936   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6937 }
6938 
6939 /*@C
6940   DMHasLabel - Determine whether the `DM` has a label of a given name
6941 
6942   Not Collective
6943 
6944   Input Parameters:
6945 + dm   - The `DM` object
6946 - name - The label name
6947 
6948   Output Parameter:
6949 . hasLabel - `PETSC_TRUE` if the label is present
6950 
6951   Level: intermediate
6952 
6953 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6954 @*/
6955 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6956 {
6957   DMLabelLink next = dm->labels;
6958   const char *lname;
6959 
6960   PetscFunctionBegin;
6961   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6962   PetscAssertPointer(name, 2);
6963   PetscAssertPointer(hasLabel, 3);
6964   *hasLabel = PETSC_FALSE;
6965   while (next) {
6966     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
6967     PetscCall(PetscStrcmp(name, lname, hasLabel));
6968     if (*hasLabel) break;
6969     next = next->next;
6970   }
6971   PetscFunctionReturn(PETSC_SUCCESS);
6972 }
6973 
6974 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
6975 /*@C
6976   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
6977 
6978   Not Collective
6979 
6980   Input Parameters:
6981 + dm   - The `DM` object
6982 - name - The label name
6983 
6984   Output Parameter:
6985 . label - The `DMLabel`, or `NULL` if the label is absent
6986 
6987   Default labels in a `DMPLEX`:
6988 + "depth"       - Holds the depth (co-dimension) of each mesh point
6989 . "celltype"    - Holds the topological type of each cell
6990 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6991 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
6992 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
6993 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
6994 
6995   Level: intermediate
6996 
6997 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6998 @*/
6999 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7000 {
7001   DMLabelLink next = dm->labels;
7002   PetscBool   hasLabel;
7003   const char *lname;
7004 
7005   PetscFunctionBegin;
7006   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7007   PetscAssertPointer(name, 2);
7008   PetscAssertPointer(label, 3);
7009   *label = NULL;
7010   while (next) {
7011     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7012     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7013     if (hasLabel) {
7014       *label = next->label;
7015       break;
7016     }
7017     next = next->next;
7018   }
7019   PetscFunctionReturn(PETSC_SUCCESS);
7020 }
7021 
7022 /*@C
7023   DMGetLabelByNum - Return the nth label on a `DM`
7024 
7025   Not Collective
7026 
7027   Input Parameters:
7028 + dm - The `DM` object
7029 - n  - the label number
7030 
7031   Output Parameter:
7032 . label - the label
7033 
7034   Level: intermediate
7035 
7036 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7037 @*/
7038 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7039 {
7040   DMLabelLink next = dm->labels;
7041   PetscInt    l    = 0;
7042 
7043   PetscFunctionBegin;
7044   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7045   PetscAssertPointer(label, 3);
7046   while (next) {
7047     if (l == n) {
7048       *label = next->label;
7049       PetscFunctionReturn(PETSC_SUCCESS);
7050     }
7051     ++l;
7052     next = next->next;
7053   }
7054   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7055 }
7056 
7057 /*@C
7058   DMAddLabel - Add the label to this `DM`
7059 
7060   Not Collective
7061 
7062   Input Parameters:
7063 + dm    - The `DM` object
7064 - label - The `DMLabel`
7065 
7066   Level: developer
7067 
7068 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7069 @*/
7070 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7071 {
7072   DMLabelLink l, *p, tmpLabel;
7073   PetscBool   hasLabel;
7074   const char *lname;
7075   PetscBool   flg;
7076 
7077   PetscFunctionBegin;
7078   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7079   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7080   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7081   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7082   PetscCall(PetscCalloc1(1, &tmpLabel));
7083   tmpLabel->label  = label;
7084   tmpLabel->output = PETSC_TRUE;
7085   for (p = &dm->labels; (l = *p); p = &l->next) { }
7086   *p = tmpLabel;
7087   PetscCall(PetscObjectReference((PetscObject)label));
7088   PetscCall(PetscStrcmp(lname, "depth", &flg));
7089   if (flg) dm->depthLabel = label;
7090   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7091   if (flg) dm->celltypeLabel = label;
7092   PetscFunctionReturn(PETSC_SUCCESS);
7093 }
7094 
7095 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown
7096 /*@C
7097   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7098 
7099   Not Collective
7100 
7101   Input Parameters:
7102 + dm    - The `DM` object
7103 - label - The `DMLabel`, having the same name, to substitute
7104 
7105   Default labels in a `DMPLEX`:
7106 + "depth"       - Holds the depth (co-dimension) of each mesh point
7107 . "celltype"    - Holds the topological type of each cell
7108 . "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7109 . "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7110 . "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7111 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7112 
7113   Level: intermediate
7114 
7115 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7116 @*/
7117 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7118 {
7119   DMLabelLink next = dm->labels;
7120   PetscBool   hasLabel, flg;
7121   const char *name, *lname;
7122 
7123   PetscFunctionBegin;
7124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7125   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7126   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7127   while (next) {
7128     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7129     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7130     if (hasLabel) {
7131       PetscCall(PetscObjectReference((PetscObject)label));
7132       PetscCall(PetscStrcmp(lname, "depth", &flg));
7133       if (flg) dm->depthLabel = label;
7134       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7135       if (flg) dm->celltypeLabel = label;
7136       PetscCall(DMLabelDestroy(&next->label));
7137       next->label = label;
7138       break;
7139     }
7140     next = next->next;
7141   }
7142   PetscFunctionReturn(PETSC_SUCCESS);
7143 }
7144 
7145 /*@C
7146   DMRemoveLabel - Remove the label given by name from this `DM`
7147 
7148   Not Collective
7149 
7150   Input Parameters:
7151 + dm   - The `DM` object
7152 - name - The label name
7153 
7154   Output Parameter:
7155 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7156           caller is responsible for calling `DMLabelDestroy()`.
7157 
7158   Level: developer
7159 
7160 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7161 @*/
7162 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7163 {
7164   DMLabelLink link, *pnext;
7165   PetscBool   hasLabel;
7166   const char *lname;
7167 
7168   PetscFunctionBegin;
7169   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7170   PetscAssertPointer(name, 2);
7171   if (label) {
7172     PetscAssertPointer(label, 3);
7173     *label = NULL;
7174   }
7175   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7176     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7177     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7178     if (hasLabel) {
7179       *pnext = link->next; /* Remove from list */
7180       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7181       if (hasLabel) dm->depthLabel = NULL;
7182       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7183       if (hasLabel) dm->celltypeLabel = NULL;
7184       if (label) *label = link->label;
7185       else PetscCall(DMLabelDestroy(&link->label));
7186       PetscCall(PetscFree(link));
7187       break;
7188     }
7189   }
7190   PetscFunctionReturn(PETSC_SUCCESS);
7191 }
7192 
7193 /*@
7194   DMRemoveLabelBySelf - Remove the label from this `DM`
7195 
7196   Not Collective
7197 
7198   Input Parameters:
7199 + dm           - The `DM` object
7200 . label        - The `DMLabel` to be removed from the `DM`
7201 - failNotFound - Should it fail if the label is not found in the `DM`?
7202 
7203   Level: developer
7204 
7205   Note:
7206   Only exactly the same instance is removed if found, name match is ignored.
7207   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7208   *label nullified.
7209 
7210 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7211 @*/
7212 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7213 {
7214   DMLabelLink link, *pnext;
7215   PetscBool   hasLabel = PETSC_FALSE;
7216 
7217   PetscFunctionBegin;
7218   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7219   PetscAssertPointer(label, 2);
7220   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7221   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7222   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7223   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7224     if (*label == link->label) {
7225       hasLabel = PETSC_TRUE;
7226       *pnext   = link->next; /* Remove from list */
7227       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7228       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7229       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7230       PetscCall(DMLabelDestroy(&link->label));
7231       PetscCall(PetscFree(link));
7232       break;
7233     }
7234   }
7235   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7236   PetscFunctionReturn(PETSC_SUCCESS);
7237 }
7238 
7239 /*@C
7240   DMGetLabelOutput - Get the output flag for a given label
7241 
7242   Not Collective
7243 
7244   Input Parameters:
7245 + dm   - The `DM` object
7246 - name - The label name
7247 
7248   Output Parameter:
7249 . output - The flag for output
7250 
7251   Level: developer
7252 
7253 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7254 @*/
7255 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7256 {
7257   DMLabelLink next = dm->labels;
7258   const char *lname;
7259 
7260   PetscFunctionBegin;
7261   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7262   PetscAssertPointer(name, 2);
7263   PetscAssertPointer(output, 3);
7264   while (next) {
7265     PetscBool flg;
7266 
7267     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7268     PetscCall(PetscStrcmp(name, lname, &flg));
7269     if (flg) {
7270       *output = next->output;
7271       PetscFunctionReturn(PETSC_SUCCESS);
7272     }
7273     next = next->next;
7274   }
7275   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7276 }
7277 
7278 /*@C
7279   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7280 
7281   Not Collective
7282 
7283   Input Parameters:
7284 + dm     - The `DM` object
7285 . name   - The label name
7286 - output - `PETSC_TRUE` to save the label to the viewer
7287 
7288   Level: developer
7289 
7290 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7291 @*/
7292 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7293 {
7294   DMLabelLink next = dm->labels;
7295   const char *lname;
7296 
7297   PetscFunctionBegin;
7298   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7299   PetscAssertPointer(name, 2);
7300   while (next) {
7301     PetscBool flg;
7302 
7303     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7304     PetscCall(PetscStrcmp(name, lname, &flg));
7305     if (flg) {
7306       next->output = output;
7307       PetscFunctionReturn(PETSC_SUCCESS);
7308     }
7309     next = next->next;
7310   }
7311   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7312 }
7313 
7314 /*@
7315   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7316 
7317   Collective
7318 
7319   Input Parameters:
7320 + dmA   - The `DM` object with initial labels
7321 . dmB   - The `DM` object to which labels are copied
7322 . mode  - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7323 . all   - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7324 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7325 
7326   Level: intermediate
7327 
7328   Note:
7329   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7330 
7331 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7332 @*/
7333 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7334 {
7335   DMLabel     label, labelNew, labelOld;
7336   const char *name;
7337   PetscBool   flg;
7338   DMLabelLink link;
7339 
7340   PetscFunctionBegin;
7341   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7342   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7343   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7344   PetscValidLogicalCollectiveBool(dmA, all, 4);
7345   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7346   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7347   for (link = dmA->labels; link; link = link->next) {
7348     label = link->label;
7349     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7350     if (!all) {
7351       PetscCall(PetscStrcmp(name, "depth", &flg));
7352       if (flg) continue;
7353       PetscCall(PetscStrcmp(name, "dim", &flg));
7354       if (flg) continue;
7355       PetscCall(PetscStrcmp(name, "celltype", &flg));
7356       if (flg) continue;
7357     }
7358     PetscCall(DMGetLabel(dmB, name, &labelOld));
7359     if (labelOld) {
7360       switch (emode) {
7361       case DM_COPY_LABELS_KEEP:
7362         continue;
7363       case DM_COPY_LABELS_REPLACE:
7364         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7365         break;
7366       case DM_COPY_LABELS_FAIL:
7367         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7368       default:
7369         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7370       }
7371     }
7372     if (mode == PETSC_COPY_VALUES) {
7373       PetscCall(DMLabelDuplicate(label, &labelNew));
7374     } else {
7375       labelNew = label;
7376     }
7377     PetscCall(DMAddLabel(dmB, labelNew));
7378     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7379   }
7380   PetscFunctionReturn(PETSC_SUCCESS);
7381 }
7382 
7383 /*@C
7384   DMCompareLabels - Compare labels between two `DM` objects
7385 
7386   Collective; No Fortran Support
7387 
7388   Input Parameters:
7389 + dm0 - First `DM` object
7390 - dm1 - Second `DM` object
7391 
7392   Output Parameters:
7393 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7394 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7395 
7396   Level: intermediate
7397 
7398   Notes:
7399   The output flag equal will be the same on all processes.
7400 
7401   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7402 
7403   Make sure to pass equal is `NULL` on all processes or none of them.
7404 
7405   The output message is set independently on each rank.
7406 
7407   message must be freed with `PetscFree()`
7408 
7409   If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner.
7410 
7411   Make sure to pass message as `NULL` on all processes or no processes.
7412 
7413   Labels are matched by name. If the number of labels and their names are equal,
7414   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7415 
7416 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7417 @*/
7418 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7419 {
7420   PetscInt    n, i;
7421   char        msg[PETSC_MAX_PATH_LEN] = "";
7422   PetscBool   eq;
7423   MPI_Comm    comm;
7424   PetscMPIInt rank;
7425 
7426   PetscFunctionBegin;
7427   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7428   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7429   PetscCheckSameComm(dm0, 1, dm1, 2);
7430   if (equal) PetscAssertPointer(equal, 3);
7431   if (message) PetscAssertPointer(message, 4);
7432   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7433   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7434   {
7435     PetscInt n1;
7436 
7437     PetscCall(DMGetNumLabels(dm0, &n));
7438     PetscCall(DMGetNumLabels(dm1, &n1));
7439     eq = (PetscBool)(n == n1);
7440     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7441     PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7442     if (!eq) goto finish;
7443   }
7444   for (i = 0; i < n; i++) {
7445     DMLabel     l0, l1;
7446     const char *name;
7447     char       *msgInner;
7448 
7449     /* Ignore label order */
7450     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7451     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7452     PetscCall(DMGetLabel(dm1, name, &l1));
7453     if (!l1) {
7454       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7455       eq = PETSC_FALSE;
7456       break;
7457     }
7458     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7459     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7460     PetscCall(PetscFree(msgInner));
7461     if (!eq) break;
7462   }
7463   PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7464 finish:
7465   /* If message output arg not set, print to stderr */
7466   if (message) {
7467     *message = NULL;
7468     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7469   } else {
7470     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7471     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7472   }
7473   /* If same output arg not ser and labels are not equal, throw error */
7474   if (equal) *equal = eq;
7475   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7476   PetscFunctionReturn(PETSC_SUCCESS);
7477 }
7478 
7479 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7480 {
7481   PetscFunctionBegin;
7482   PetscAssertPointer(label, 2);
7483   if (!*label) {
7484     PetscCall(DMCreateLabel(dm, name));
7485     PetscCall(DMGetLabel(dm, name, label));
7486   }
7487   PetscCall(DMLabelSetValue(*label, point, value));
7488   PetscFunctionReturn(PETSC_SUCCESS);
7489 }
7490 
7491 /*
7492   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7493   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7494   (label, id) pair in the DM.
7495 
7496   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7497   each label.
7498 */
7499 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7500 {
7501   DMUniversalLabel ul;
7502   PetscBool       *active;
7503   PetscInt         pStart, pEnd, p, Nl, l, m;
7504 
7505   PetscFunctionBegin;
7506   PetscCall(PetscMalloc1(1, &ul));
7507   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7508   PetscCall(DMGetNumLabels(dm, &Nl));
7509   PetscCall(PetscCalloc1(Nl, &active));
7510   ul->Nl = 0;
7511   for (l = 0; l < Nl; ++l) {
7512     PetscBool   isdepth, iscelltype;
7513     const char *name;
7514 
7515     PetscCall(DMGetLabelName(dm, l, &name));
7516     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7517     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7518     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7519     if (active[l]) ++ul->Nl;
7520   }
7521   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7522   ul->Nv = 0;
7523   for (l = 0, m = 0; l < Nl; ++l) {
7524     DMLabel     label;
7525     PetscInt    nv;
7526     const char *name;
7527 
7528     if (!active[l]) continue;
7529     PetscCall(DMGetLabelName(dm, l, &name));
7530     PetscCall(DMGetLabelByNum(dm, l, &label));
7531     PetscCall(DMLabelGetNumValues(label, &nv));
7532     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7533     ul->indices[m] = l;
7534     ul->Nv += nv;
7535     ul->offsets[m + 1] = nv;
7536     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7537     ++m;
7538   }
7539   for (l = 1; l <= ul->Nl; ++l) {
7540     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7541     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7542   }
7543   for (l = 0; l < ul->Nl; ++l) {
7544     PetscInt b;
7545 
7546     ul->masks[l] = 0;
7547     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7548   }
7549   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7550   for (l = 0, m = 0; l < Nl; ++l) {
7551     DMLabel         label;
7552     IS              valueIS;
7553     const PetscInt *varr;
7554     PetscInt        nv, v;
7555 
7556     if (!active[l]) continue;
7557     PetscCall(DMGetLabelByNum(dm, l, &label));
7558     PetscCall(DMLabelGetNumValues(label, &nv));
7559     PetscCall(DMLabelGetValueIS(label, &valueIS));
7560     PetscCall(ISGetIndices(valueIS, &varr));
7561     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7562     PetscCall(ISRestoreIndices(valueIS, &varr));
7563     PetscCall(ISDestroy(&valueIS));
7564     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7565     ++m;
7566   }
7567   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7568   for (p = pStart; p < pEnd; ++p) {
7569     PetscInt  uval   = 0;
7570     PetscBool marked = PETSC_FALSE;
7571 
7572     for (l = 0, m = 0; l < Nl; ++l) {
7573       DMLabel  label;
7574       PetscInt val, defval, loc, nv;
7575 
7576       if (!active[l]) continue;
7577       PetscCall(DMGetLabelByNum(dm, l, &label));
7578       PetscCall(DMLabelGetValue(label, p, &val));
7579       PetscCall(DMLabelGetDefaultValue(label, &defval));
7580       if (val == defval) {
7581         ++m;
7582         continue;
7583       }
7584       nv     = ul->offsets[m + 1] - ul->offsets[m];
7585       marked = PETSC_TRUE;
7586       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7587       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7588       uval += (loc + 1) << ul->bits[m];
7589       ++m;
7590     }
7591     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7592   }
7593   PetscCall(PetscFree(active));
7594   *universal = ul;
7595   PetscFunctionReturn(PETSC_SUCCESS);
7596 }
7597 
7598 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7599 {
7600   PetscInt l;
7601 
7602   PetscFunctionBegin;
7603   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7604   PetscCall(DMLabelDestroy(&(*universal)->label));
7605   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7606   PetscCall(PetscFree((*universal)->values));
7607   PetscCall(PetscFree(*universal));
7608   *universal = NULL;
7609   PetscFunctionReturn(PETSC_SUCCESS);
7610 }
7611 
7612 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7613 {
7614   PetscFunctionBegin;
7615   PetscAssertPointer(ulabel, 2);
7616   *ulabel = ul->label;
7617   PetscFunctionReturn(PETSC_SUCCESS);
7618 }
7619 
7620 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7621 {
7622   PetscInt Nl = ul->Nl, l;
7623 
7624   PetscFunctionBegin;
7625   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7626   for (l = 0; l < Nl; ++l) {
7627     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7628     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7629   }
7630   if (preserveOrder) {
7631     for (l = 0; l < ul->Nl; ++l) {
7632       const char *name;
7633       PetscBool   match;
7634 
7635       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7636       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7637       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]);
7638     }
7639   }
7640   PetscFunctionReturn(PETSC_SUCCESS);
7641 }
7642 
7643 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7644 {
7645   PetscInt l;
7646 
7647   PetscFunctionBegin;
7648   for (l = 0; l < ul->Nl; ++l) {
7649     DMLabel  label;
7650     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7651 
7652     if (lval) {
7653       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7654       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7655       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7656     }
7657   }
7658   PetscFunctionReturn(PETSC_SUCCESS);
7659 }
7660 
7661 /*@
7662   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7663 
7664   Not Collective
7665 
7666   Input Parameter:
7667 . dm - The `DM` object
7668 
7669   Output Parameter:
7670 . cdm - The coarse `DM`
7671 
7672   Level: intermediate
7673 
7674 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()`
7675 @*/
7676 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7677 {
7678   PetscFunctionBegin;
7679   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7680   PetscAssertPointer(cdm, 2);
7681   *cdm = dm->coarseMesh;
7682   PetscFunctionReturn(PETSC_SUCCESS);
7683 }
7684 
7685 /*@
7686   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7687 
7688   Input Parameters:
7689 + dm  - The `DM` object
7690 - cdm - The coarse `DM`
7691 
7692   Level: intermediate
7693 
7694   Note:
7695   Normally this is set automatically by `DMRefine()`
7696 
7697 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7698 @*/
7699 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7700 {
7701   PetscFunctionBegin;
7702   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7703   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7704   if (dm == cdm) cdm = NULL;
7705   PetscCall(PetscObjectReference((PetscObject)cdm));
7706   PetscCall(DMDestroy(&dm->coarseMesh));
7707   dm->coarseMesh = cdm;
7708   PetscFunctionReturn(PETSC_SUCCESS);
7709 }
7710 
7711 /*@
7712   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7713 
7714   Input Parameter:
7715 . dm - The `DM` object
7716 
7717   Output Parameter:
7718 . fdm - The fine `DM`
7719 
7720   Level: intermediate
7721 
7722 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7723 @*/
7724 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7725 {
7726   PetscFunctionBegin;
7727   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7728   PetscAssertPointer(fdm, 2);
7729   *fdm = dm->fineMesh;
7730   PetscFunctionReturn(PETSC_SUCCESS);
7731 }
7732 
7733 /*@
7734   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7735 
7736   Input Parameters:
7737 + dm  - The `DM` object
7738 - fdm - The fine `DM`
7739 
7740   Level: developer
7741 
7742   Note:
7743   Normally this is set automatically by `DMCoarsen()`
7744 
7745 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7746 @*/
7747 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7748 {
7749   PetscFunctionBegin;
7750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7751   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7752   if (dm == fdm) fdm = NULL;
7753   PetscCall(PetscObjectReference((PetscObject)fdm));
7754   PetscCall(DMDestroy(&dm->fineMesh));
7755   dm->fineMesh = fdm;
7756   PetscFunctionReturn(PETSC_SUCCESS);
7757 }
7758 
7759 /*@C
7760   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7761 
7762   Collective
7763 
7764   Input Parameters:
7765 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7766 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7767 . name     - The BC name
7768 . label    - The label defining constrained points
7769 . Nv       - The number of `DMLabel` values for constrained points
7770 . values   - An array of values for constrained points
7771 . field    - The field to constrain
7772 . Nc       - The number of constrained field components (0 will constrain all fields)
7773 . comps    - An array of constrained component numbers
7774 . bcFunc   - A pointwise function giving boundary values
7775 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7776 - ctx      - An optional user context for bcFunc
7777 
7778   Output Parameter:
7779 . bd - (Optional) Boundary number
7780 
7781   Options Database Keys:
7782 + -bc_<boundary name> <num>      - Overrides the boundary ids
7783 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7784 
7785   Level: intermediate
7786 
7787   Notes:
7788   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\:
7789 
7790 $ void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
7791 
7792   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\:
7793 
7794 .vb
7795   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7796               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7797               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7798               PetscReal time, const PetscReal x[], PetscScalar bcval[])
7799 .ve
7800 + dim - the spatial dimension
7801 . Nf - the number of fields
7802 . uOff - the offset into u[] and u_t[] for each field
7803 . uOff_x - the offset into u_x[] for each field
7804 . u - each field evaluated at the current point
7805 . u_t - the time derivative of each field evaluated at the current point
7806 . u_x - the gradient of each field evaluated at the current point
7807 . aOff - the offset into a[] and a_t[] for each auxiliary field
7808 . aOff_x - the offset into a_x[] for each auxiliary field
7809 . a - each auxiliary field evaluated at the current point
7810 . a_t - the time derivative of each auxiliary field evaluated at the current point
7811 . a_x - the gradient of auxiliary each field evaluated at the current point
7812 . t - current time
7813 . x - coordinates of the current point
7814 . numConstants - number of constant parameters
7815 . constants - constant parameters
7816 - bcval - output values at the current point
7817 
7818 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()`
7819 @*/
7820 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)
7821 {
7822   PetscDS ds;
7823 
7824   PetscFunctionBegin;
7825   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7826   PetscValidLogicalCollectiveEnum(dm, type, 2);
7827   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
7828   PetscValidLogicalCollectiveInt(dm, Nv, 5);
7829   PetscValidLogicalCollectiveInt(dm, field, 7);
7830   PetscValidLogicalCollectiveInt(dm, Nc, 8);
7831   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
7832   PetscCall(DMGetDS(dm, &ds));
7833   /* Complete label */
7834   if (label) {
7835     PetscObject  obj;
7836     PetscClassId id;
7837 
7838     PetscCall(DMGetField(dm, field, NULL, &obj));
7839     PetscCall(PetscObjectGetClassId(obj, &id));
7840     if (id == PETSCFE_CLASSID) {
7841       DM plex;
7842 
7843       PetscCall(DMConvert(dm, DMPLEX, &plex));
7844       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
7845       PetscCall(DMDestroy(&plex));
7846     }
7847   }
7848   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
7849   PetscFunctionReturn(PETSC_SUCCESS);
7850 }
7851 
7852 /* TODO Remove this since now the structures are the same */
7853 static PetscErrorCode DMPopulateBoundary(DM dm)
7854 {
7855   PetscDS     ds;
7856   DMBoundary *lastnext;
7857   DSBoundary  dsbound;
7858 
7859   PetscFunctionBegin;
7860   PetscCall(DMGetDS(dm, &ds));
7861   dsbound = ds->boundary;
7862   if (dm->boundary) {
7863     DMBoundary next = dm->boundary;
7864 
7865     /* quick check to see if the PetscDS has changed */
7866     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
7867     /* the PetscDS has changed: tear down and rebuild */
7868     while (next) {
7869       DMBoundary b = next;
7870 
7871       next = b->next;
7872       PetscCall(PetscFree(b));
7873     }
7874     dm->boundary = NULL;
7875   }
7876 
7877   lastnext = &(dm->boundary);
7878   while (dsbound) {
7879     DMBoundary dmbound;
7880 
7881     PetscCall(PetscNew(&dmbound));
7882     dmbound->dsboundary = dsbound;
7883     dmbound->label      = dsbound->label;
7884     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7885     *lastnext = dmbound;
7886     lastnext  = &(dmbound->next);
7887     dsbound   = dsbound->next;
7888   }
7889   PetscFunctionReturn(PETSC_SUCCESS);
7890 }
7891 
7892 /* TODO: missing manual page */
7893 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7894 {
7895   DMBoundary b;
7896 
7897   PetscFunctionBegin;
7898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7899   PetscAssertPointer(isBd, 3);
7900   *isBd = PETSC_FALSE;
7901   PetscCall(DMPopulateBoundary(dm));
7902   b = dm->boundary;
7903   while (b && !(*isBd)) {
7904     DMLabel    label = b->label;
7905     DSBoundary dsb   = b->dsboundary;
7906     PetscInt   i;
7907 
7908     if (label) {
7909       for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
7910     }
7911     b = b->next;
7912   }
7913   PetscFunctionReturn(PETSC_SUCCESS);
7914 }
7915 
7916 /*@C
7917   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
7918 
7919   Collective
7920 
7921   Input Parameters:
7922 + dm    - The `DM`
7923 . time  - The time
7924 . funcs - The coordinate functions to evaluate, one per field
7925 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7926 - mode  - The insertion mode for values
7927 
7928   Output Parameter:
7929 . X - vector
7930 
7931   Calling sequence of `funcs`:
7932 + dim  - The spatial dimension
7933 . time - The time at which to sample
7934 . x    - The coordinates
7935 . Nc   - The number of components
7936 . u    - The output field values
7937 - ctx  - optional user-defined function context
7938 
7939   Level: developer
7940 
7941   Developer Notes:
7942   This API is specific to only particular usage of `DM`
7943 
7944   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7945 
7946 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7947 @*/
7948 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)
7949 {
7950   Vec localX;
7951 
7952   PetscFunctionBegin;
7953   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7954   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
7955   PetscCall(DMGetLocalVector(dm, &localX));
7956   PetscCall(VecSet(localX, 0.));
7957   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
7958   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
7959   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
7960   PetscCall(DMRestoreLocalVector(dm, &localX));
7961   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
7962   PetscFunctionReturn(PETSC_SUCCESS);
7963 }
7964 
7965 /*@C
7966   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
7967 
7968   Not Collective
7969 
7970   Input Parameters:
7971 + dm    - The `DM`
7972 . time  - The time
7973 . funcs - The coordinate functions to evaluate, one per field
7974 . ctxs  - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7975 - mode  - The insertion mode for values
7976 
7977   Output Parameter:
7978 . localX - vector
7979 
7980   Calling sequence of `funcs`:
7981 + dim  - The spatial dimension
7982 . time - The current timestep
7983 . x    - The coordinates
7984 . Nc   - The number of components
7985 . u    - The output field values
7986 - ctx  - optional user-defined function context
7987 
7988   Level: developer
7989 
7990   Developer Notes:
7991   This API is specific to only particular usage of `DM`
7992 
7993   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7994 
7995 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7996 @*/
7997 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)
7998 {
7999   PetscFunctionBegin;
8000   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8001   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8002   PetscCall((dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX));
8003   PetscFunctionReturn(PETSC_SUCCESS);
8004 }
8005 
8006 /*@C
8007   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.
8008 
8009   Collective
8010 
8011   Input Parameters:
8012 + dm     - The `DM`
8013 . time   - The time
8014 . numIds - The number of ids
8015 . ids    - The ids
8016 . Nc     - The number of components
8017 . comps  - The components
8018 . label  - The `DMLabel` selecting the portion of the mesh for projection
8019 . funcs  - The coordinate functions to evaluate, one per field
8020 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8021 - mode   - The insertion mode for values
8022 
8023   Output Parameter:
8024 . X - vector
8025 
8026   Calling sequence of `funcs`:
8027 + dim  - The spatial dimension
8028 . time - The current timestep
8029 . x    - The coordinates
8030 . Nc   - The number of components
8031 . u    - The output field values
8032 - ctx  - optional user-defined function context
8033 
8034   Level: developer
8035 
8036   Developer Notes:
8037   This API is specific to only particular usage of `DM`
8038 
8039   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8040 
8041 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8042 @*/
8043 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)
8044 {
8045   Vec localX;
8046 
8047   PetscFunctionBegin;
8048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8049   PetscCall(DMGetLocalVector(dm, &localX));
8050   PetscCall(VecSet(localX, 0.));
8051   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8052   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8053   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8054   PetscCall(DMRestoreLocalVector(dm, &localX));
8055   PetscFunctionReturn(PETSC_SUCCESS);
8056 }
8057 
8058 /*@C
8059   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.
8060 
8061   Not Collective
8062 
8063   Input Parameters:
8064 + dm     - The `DM`
8065 . time   - The time
8066 . label  - The `DMLabel` selecting the portion of the mesh for projection
8067 . numIds - The number of ids
8068 . ids    - The ids
8069 . Nc     - The number of components
8070 . comps  - The components
8071 . funcs  - The coordinate functions to evaluate, one per field
8072 . ctxs   - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8073 - mode   - The insertion mode for values
8074 
8075   Output Parameter:
8076 . localX - vector
8077 
8078   Calling sequence of `funcs`:
8079 + dim  - The spatial dimension
8080 . time - The current time
8081 . x    - The coordinates
8082 . Nc   - The number of components
8083 . u    - The output field values
8084 - ctx  - optional user-defined function context
8085 
8086   Level: developer
8087 
8088   Developer Notes:
8089   This API is specific to only particular usage of `DM`
8090 
8091   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8092 
8093 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8094 @*/
8095 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)
8096 {
8097   PetscFunctionBegin;
8098   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8099   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8100   PetscCall((dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8101   PetscFunctionReturn(PETSC_SUCCESS);
8102 }
8103 
8104 /*@C
8105   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.
8106 
8107   Not Collective
8108 
8109   Input Parameters:
8110 + dm     - The `DM`
8111 . time   - The time
8112 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates
8113 . funcs  - The functions to evaluate, one per field
8114 - mode   - The insertion mode for values
8115 
8116   Output Parameter:
8117 . localX - The output vector
8118 
8119   Calling sequence of `funcs`:
8120 + dim          - The spatial dimension
8121 . Nf           - The number of input fields
8122 . NfAux        - The number of input auxiliary fields
8123 . uOff         - The offset of each field in u[]
8124 . uOff_x       - The offset of each field in u_x[]
8125 . u            - The field values at this point in space
8126 . u_t          - The field time derivative at this point in space (or NULL)
8127 . u_x          - The field derivatives at this point in space
8128 . aOff         - The offset of each auxiliary field in u[]
8129 . aOff_x       - The offset of each auxiliary field in u_x[]
8130 . a            - The auxiliary field values at this point in space
8131 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8132 . a_x          - The auxiliary field derivatives at this point in space
8133 . t            - The current time
8134 . x            - The coordinates of this point
8135 . numConstants - The number of constants
8136 . constants    - The value of each constant
8137 - f            - The value of the function at this point in space
8138 
8139   Note:
8140   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.
8141   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
8142   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8143   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8144 
8145   Level: intermediate
8146 
8147   Developer Notes:
8148   This API is specific to only particular usage of `DM`
8149 
8150   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8151 
8152 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`,
8153 `DMProjectFunction()`, `DMComputeL2Diff()`
8154 @*/
8155 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)
8156 {
8157   PetscFunctionBegin;
8158   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8159   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8160   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8161   PetscCall((dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX));
8162   PetscFunctionReturn(PETSC_SUCCESS);
8163 }
8164 
8165 /*@C
8166   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.
8167 
8168   Not Collective
8169 
8170   Input Parameters:
8171 + dm     - The `DM`
8172 . time   - The time
8173 . label  - The `DMLabel` marking the portion of the domain to output
8174 . numIds - The number of label ids to use
8175 . ids    - The label ids to use for marking
8176 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8177 . comps  - The components to set in the output, or `NULL` for all components
8178 . localU - The input field vector
8179 . funcs  - The functions to evaluate, one per field
8180 - mode   - The insertion mode for values
8181 
8182   Output Parameter:
8183 . localX - The output vector
8184 
8185   Calling sequence of `funcs`:
8186 + dim          - The spatial dimension
8187 . Nf           - The number of input fields
8188 . NfAux        - The number of input auxiliary fields
8189 . uOff         - The offset of each field in u[]
8190 . uOff_x       - The offset of each field in u_x[]
8191 . u            - The field values at this point in space
8192 . u_t          - The field time derivative at this point in space (or NULL)
8193 . u_x          - The field derivatives at this point in space
8194 . aOff         - The offset of each auxiliary field in u[]
8195 . aOff_x       - The offset of each auxiliary field in u_x[]
8196 . a            - The auxiliary field values at this point in space
8197 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8198 . a_x          - The auxiliary field derivatives at this point in space
8199 . t            - The current time
8200 . x            - The coordinates of this point
8201 . numConstants - The number of constants
8202 . constants    - The value of each constant
8203 - f            - The value of the function at this point in space
8204 
8205   Note:
8206   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.
8207   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
8208   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8209   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8210 
8211   Level: intermediate
8212 
8213   Developer Notes:
8214   This API is specific to only particular usage of `DM`
8215 
8216   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8217 
8218 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8219 @*/
8220 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)
8221 {
8222   PetscFunctionBegin;
8223   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8224   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8225   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8226   PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8227   PetscFunctionReturn(PETSC_SUCCESS);
8228 }
8229 
8230 /*@C
8231   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.
8232 
8233   Not Collective
8234 
8235   Input Parameters:
8236 + dm     - The `DM`
8237 . time   - The time
8238 . label  - The `DMLabel` marking the portion of the domain to output
8239 . numIds - The number of label ids to use
8240 . ids    - The label ids to use for marking
8241 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8242 . comps  - The components to set in the output, or `NULL` for all components
8243 . U      - The input field vector
8244 . funcs  - The functions to evaluate, one per field
8245 - mode   - The insertion mode for values
8246 
8247   Output Parameter:
8248 . X - The output vector
8249 
8250   Calling sequence of `funcs`:
8251 + dim          - The spatial dimension
8252 . Nf           - The number of input fields
8253 . NfAux        - The number of input auxiliary fields
8254 . uOff         - The offset of each field in u[]
8255 . uOff_x       - The offset of each field in u_x[]
8256 . u            - The field values at this point in space
8257 . u_t          - The field time derivative at this point in space (or NULL)
8258 . u_x          - The field derivatives at this point in space
8259 . aOff         - The offset of each auxiliary field in u[]
8260 . aOff_x       - The offset of each auxiliary field in u_x[]
8261 . a            - The auxiliary field values at this point in space
8262 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8263 . a_x          - The auxiliary field derivatives at this point in space
8264 . t            - The current time
8265 . x            - The coordinates of this point
8266 . numConstants - The number of constants
8267 . constants    - The value of each constant
8268 - f            - The value of the function at this point in space
8269 
8270   Note:
8271   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.
8272   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
8273   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8274   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8275 
8276   Level: intermediate
8277 
8278   Developer Notes:
8279   This API is specific to only particular usage of `DM`
8280 
8281   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8282 
8283 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8284 @*/
8285 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)
8286 {
8287   DM  dmIn;
8288   Vec localU, localX;
8289 
8290   PetscFunctionBegin;
8291   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8292   PetscCall(VecGetDM(U, &dmIn));
8293   PetscCall(DMGetLocalVector(dmIn, &localU));
8294   PetscCall(DMGetLocalVector(dm, &localX));
8295   PetscCall(VecSet(localX, 0.));
8296   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8297   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8298   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8299   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8300   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8301   PetscCall(DMRestoreLocalVector(dm, &localX));
8302   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8303   PetscFunctionReturn(PETSC_SUCCESS);
8304 }
8305 
8306 /*@C
8307   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.
8308 
8309   Not Collective
8310 
8311   Input Parameters:
8312 + dm     - The `DM`
8313 . time   - The time
8314 . label  - The `DMLabel` marking the portion of the domain boundary to output
8315 . numIds - The number of label ids to use
8316 . ids    - The label ids to use for marking
8317 . Nc     - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8318 . comps  - The components to set in the output, or `NULL` for all components
8319 . localU - The input field vector
8320 . funcs  - The functions to evaluate, one per field
8321 - mode   - The insertion mode for values
8322 
8323   Output Parameter:
8324 . localX - The output vector
8325 
8326   Calling sequence of `funcs`:
8327 + dim          - The spatial dimension
8328 . Nf           - The number of input fields
8329 . NfAux        - The number of input auxiliary fields
8330 . uOff         - The offset of each field in u[]
8331 . uOff_x       - The offset of each field in u_x[]
8332 . u            - The field values at this point in space
8333 . u_t          - The field time derivative at this point in space (or NULL)
8334 . u_x          - The field derivatives at this point in space
8335 . aOff         - The offset of each auxiliary field in u[]
8336 . aOff_x       - The offset of each auxiliary field in u_x[]
8337 . a            - The auxiliary field values at this point in space
8338 . a_t          - The auxiliary field time derivative at this point in space (or NULL)
8339 . a_x          - The auxiliary field derivatives at this point in space
8340 . t            - The current time
8341 . x            - The coordinates of this point
8342 . n            - The face normal
8343 . numConstants - The number of constants
8344 . constants    - The value of each constant
8345 - f            - The value of the function at this point in space
8346 
8347   Note:
8348   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.
8349   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
8350   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8351   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8352 
8353   Level: intermediate
8354 
8355   Developer Notes:
8356   This API is specific to only particular usage of `DM`
8357 
8358   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8359 
8360 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8361 @*/
8362 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)
8363 {
8364   PetscFunctionBegin;
8365   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8366   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8367   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8368   PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8369   PetscFunctionReturn(PETSC_SUCCESS);
8370 }
8371 
8372 /*@C
8373   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8374 
8375   Collective
8376 
8377   Input Parameters:
8378 + dm    - The `DM`
8379 . time  - The time
8380 . funcs - The functions to evaluate for each field component
8381 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8382 - X     - The coefficient vector u_h, a global vector
8383 
8384   Output Parameter:
8385 . diff - The diff ||u - u_h||_2
8386 
8387   Level: developer
8388 
8389   Developer Notes:
8390   This API is specific to only particular usage of `DM`
8391 
8392   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8393 
8394 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8395 @*/
8396 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8397 {
8398   PetscFunctionBegin;
8399   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8400   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8401   PetscCall((dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff));
8402   PetscFunctionReturn(PETSC_SUCCESS);
8403 }
8404 
8405 /*@C
8406   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8407 
8408   Collective
8409 
8410   Input Parameters:
8411 + dm    - The `DM`
8412 . time  - The time
8413 . funcs - The gradient functions to evaluate for each field component
8414 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8415 . X     - The coefficient vector u_h, a global vector
8416 - n     - The vector to project along
8417 
8418   Output Parameter:
8419 . diff - The diff ||(grad u - grad u_h) . n||_2
8420 
8421   Level: developer
8422 
8423   Developer Notes:
8424   This API is specific to only particular usage of `DM`
8425 
8426   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8427 
8428 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8429 @*/
8430 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)
8431 {
8432   PetscFunctionBegin;
8433   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8434   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8435   PetscCall((dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff));
8436   PetscFunctionReturn(PETSC_SUCCESS);
8437 }
8438 
8439 /*@C
8440   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8441 
8442   Collective
8443 
8444   Input Parameters:
8445 + dm    - The `DM`
8446 . time  - The time
8447 . funcs - The functions to evaluate for each field component
8448 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8449 - X     - The coefficient vector u_h, a global vector
8450 
8451   Output Parameter:
8452 . diff - The array of differences, ||u^f - u^f_h||_2
8453 
8454   Level: developer
8455 
8456   Developer Notes:
8457   This API is specific to only particular usage of `DM`
8458 
8459   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8460 
8461 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()`
8462 @*/
8463 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8464 {
8465   PetscFunctionBegin;
8466   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8467   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8468   PetscCall((dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff));
8469   PetscFunctionReturn(PETSC_SUCCESS);
8470 }
8471 
8472 /*@C
8473   DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8474 
8475   Not Collective
8476 
8477   Input Parameter:
8478 . dm - The `DM`
8479 
8480   Output Parameters:
8481 + nranks - the number of neighbours
8482 - ranks  - the neighbors ranks
8483 
8484   Level: beginner
8485 
8486   Note:
8487   Do not free the array, it is freed when the `DM` is destroyed.
8488 
8489 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8490 @*/
8491 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8492 {
8493   PetscFunctionBegin;
8494   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8495   PetscCall((dm->ops->getneighbors)(dm, nranks, ranks));
8496   PetscFunctionReturn(PETSC_SUCCESS);
8497 }
8498 
8499 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8500 
8501 /*
8502     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8503     This must be a different function because it requires DM which is not defined in the Mat library
8504 */
8505 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8506 {
8507   PetscFunctionBegin;
8508   if (coloring->ctype == IS_COLORING_LOCAL) {
8509     Vec x1local;
8510     DM  dm;
8511     PetscCall(MatGetDM(J, &dm));
8512     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8513     PetscCall(DMGetLocalVector(dm, &x1local));
8514     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8515     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8516     x1 = x1local;
8517   }
8518   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8519   if (coloring->ctype == IS_COLORING_LOCAL) {
8520     DM dm;
8521     PetscCall(MatGetDM(J, &dm));
8522     PetscCall(DMRestoreLocalVector(dm, &x1));
8523   }
8524   PetscFunctionReturn(PETSC_SUCCESS);
8525 }
8526 
8527 /*@
8528   MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8529 
8530   Input Parameters:
8531 + coloring   - The matrix to get the `DM` from
8532 - fdcoloring - the `MatFDColoring` object
8533 
8534   Level: advanced
8535 
8536   Developer Notes:
8537   this routine exists because the PETSc `Mat` library does not know about the `DM` objects
8538 
8539 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8540 @*/
8541 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8542 {
8543   PetscFunctionBegin;
8544   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8545   PetscFunctionReturn(PETSC_SUCCESS);
8546 }
8547 
8548 /*@
8549   DMGetCompatibility - determine if two `DM`s are compatible
8550 
8551   Collective
8552 
8553   Input Parameters:
8554 + dm1 - the first `DM`
8555 - dm2 - the second `DM`
8556 
8557   Output Parameters:
8558 + compatible - whether or not the two `DM`s are compatible
8559 - set        - whether or not the compatible value was actually determined and set
8560 
8561   Level: advanced
8562 
8563   Notes:
8564   Two `DM`s are deemed compatible if they represent the same parallel decomposition
8565   of the same topology. This implies that the section (field data) on one
8566   "makes sense" with respect to the topology and parallel decomposition of the other.
8567   Loosely speaking, compatible `DM`s represent the same domain and parallel
8568   decomposition, but hold different data.
8569 
8570   Typically, one would confirm compatibility if intending to simultaneously iterate
8571   over a pair of vectors obtained from different `DM`s.
8572 
8573   For example, two `DMDA` objects are compatible if they have the same local
8574   and global sizes and the same stencil width. They can have different numbers
8575   of degrees of freedom per node. Thus, one could use the node numbering from
8576   either `DM` in bounds for a loop over vectors derived from either `DM`.
8577 
8578   Consider the operation of summing data living on a 2-dof `DMDA` to data living
8579   on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8580 .vb
8581   ...
8582   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8583   if (set && compatible)  {
8584     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8585     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8586     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8587     for (j=y; j<y+n; ++j) {
8588       for (i=x; i<x+m, ++i) {
8589         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8590       }
8591     }
8592     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8593     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8594   } else {
8595     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8596   }
8597   ...
8598 .ve
8599 
8600   Checking compatibility might be expensive for a given implementation of `DM`,
8601   or might be impossible to unambiguously confirm or deny. For this reason,
8602   this function may decline to determine compatibility, and hence users should
8603   always check the "set" output parameter.
8604 
8605   A `DM` is always compatible with itself.
8606 
8607   In the current implementation, `DM`s which live on "unequal" communicators
8608   (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8609   incompatible.
8610 
8611   This function is labeled "Collective," as information about all subdomains
8612   is required on each rank. However, in `DM` implementations which store all this
8613   information locally, this function may be merely "Logically Collective".
8614 
8615   Developer Notes:
8616   Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8617   iff B is compatible with A. Thus, this function checks the implementations
8618   of both dm and dmc (if they are of different types), attempting to determine
8619   compatibility. It is left to `DM` implementers to ensure that symmetry is
8620   preserved. The simplest way to do this is, when implementing type-specific
8621   logic for this function, is to check for existing logic in the implementation
8622   of other `DM` types and let *set = PETSC_FALSE if found.
8623 
8624 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8625 @*/
8626 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8627 {
8628   PetscMPIInt compareResult;
8629   DMType      type, type2;
8630   PetscBool   sameType;
8631 
8632   PetscFunctionBegin;
8633   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8634   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8635 
8636   /* Declare a DM compatible with itself */
8637   if (dm1 == dm2) {
8638     *set        = PETSC_TRUE;
8639     *compatible = PETSC_TRUE;
8640     PetscFunctionReturn(PETSC_SUCCESS);
8641   }
8642 
8643   /* Declare a DM incompatible with a DM that lives on an "unequal"
8644      communicator. Note that this does not preclude compatibility with
8645      DMs living on "congruent" or "similar" communicators, but this must be
8646      determined by the implementation-specific logic */
8647   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8648   if (compareResult == MPI_UNEQUAL) {
8649     *set        = PETSC_TRUE;
8650     *compatible = PETSC_FALSE;
8651     PetscFunctionReturn(PETSC_SUCCESS);
8652   }
8653 
8654   /* Pass to the implementation-specific routine, if one exists. */
8655   if (dm1->ops->getcompatibility) {
8656     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8657     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8658   }
8659 
8660   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8661      with an implementation of this function from dm2 */
8662   PetscCall(DMGetType(dm1, &type));
8663   PetscCall(DMGetType(dm2, &type2));
8664   PetscCall(PetscStrcmp(type, type2, &sameType));
8665   if (!sameType && dm2->ops->getcompatibility) {
8666     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8667   } else {
8668     *set = PETSC_FALSE;
8669   }
8670   PetscFunctionReturn(PETSC_SUCCESS);
8671 }
8672 
8673 /*@C
8674   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8675 
8676   Logically Collective
8677 
8678   Input Parameters:
8679 + dm             - the `DM`
8680 . f              - the monitor function
8681 . mctx           - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8682 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`)
8683 
8684   Options Database Key:
8685 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8686                             does not cancel those set via the options database.
8687 
8688   Level: intermediate
8689 
8690   Note:
8691   Several different monitoring routines may be set by calling
8692   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8693   order in which they were set.
8694 
8695   Fortran Notes:
8696   Only a single monitor function can be set for each `DM` object
8697 
8698   Developer Notes:
8699   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8700 
8701 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8702 @*/
8703 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8704 {
8705   PetscInt m;
8706 
8707   PetscFunctionBegin;
8708   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8709   for (m = 0; m < dm->numbermonitors; ++m) {
8710     PetscBool identical;
8711 
8712     PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8713     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
8714   }
8715   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8716   dm->monitor[dm->numbermonitors]          = f;
8717   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8718   dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8719   PetscFunctionReturn(PETSC_SUCCESS);
8720 }
8721 
8722 /*@
8723   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8724 
8725   Logically Collective
8726 
8727   Input Parameter:
8728 . dm - the DM
8729 
8730   Options Database Key:
8731 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8732   into a code by calls to `DMonitorSet()`, but does not cancel those
8733   set via the options database
8734 
8735   Level: intermediate
8736 
8737   Note:
8738   There is no way to clear one specific monitor from a `DM` object.
8739 
8740 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8741 @*/
8742 PetscErrorCode DMMonitorCancel(DM dm)
8743 {
8744   PetscInt m;
8745 
8746   PetscFunctionBegin;
8747   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8748   for (m = 0; m < dm->numbermonitors; ++m) {
8749     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8750   }
8751   dm->numbermonitors = 0;
8752   PetscFunctionReturn(PETSC_SUCCESS);
8753 }
8754 
8755 /*@C
8756   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8757 
8758   Collective
8759 
8760   Input Parameters:
8761 + dm           - `DM` object you wish to monitor
8762 . name         - the monitor type one is seeking
8763 . help         - message indicating what monitoring is done
8764 . manual       - manual page for the monitor
8765 . monitor      - the monitor function
8766 - 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
8767 
8768   Output Parameter:
8769 . flg - Flag set if the monitor was created
8770 
8771   Level: developer
8772 
8773 .seealso: [](ch_dmbase), `DM`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8774           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8775           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
8776           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8777           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8778           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8779           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8780 @*/
8781 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8782 {
8783   PetscViewer       viewer;
8784   PetscViewerFormat format;
8785 
8786   PetscFunctionBegin;
8787   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8788   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
8789   if (*flg) {
8790     PetscViewerAndFormat *vf;
8791 
8792     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
8793     PetscCall(PetscObjectDereference((PetscObject)viewer));
8794     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
8795     PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
8796   }
8797   PetscFunctionReturn(PETSC_SUCCESS);
8798 }
8799 
8800 /*@
8801   DMMonitor - runs the user provided monitor routines, if they exist
8802 
8803   Collective
8804 
8805   Input Parameter:
8806 . dm - The `DM`
8807 
8808   Level: developer
8809 
8810   Developer Notes:
8811   Note should indicate when during the life of the `DM` the monitor is run. It appears to be
8812   related to the discretization process seems rather specialized since some `DM` have no
8813   concept of discretization.
8814 
8815 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`
8816 @*/
8817 PetscErrorCode DMMonitor(DM dm)
8818 {
8819   PetscInt m;
8820 
8821   PetscFunctionBegin;
8822   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
8823   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8824   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
8825   PetscFunctionReturn(PETSC_SUCCESS);
8826 }
8827 
8828 /*@
8829   DMComputeError - Computes the error assuming the user has provided the exact solution functions
8830 
8831   Collective
8832 
8833   Input Parameters:
8834 + dm  - The `DM`
8835 - sol - The solution vector
8836 
8837   Input/Output Parameter:
8838 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
8839            contains the error in each field
8840 
8841   Output Parameter:
8842 . errorVec - A vector to hold the cellwise error (may be `NULL`)
8843 
8844   Level: developer
8845 
8846   Note:
8847   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
8848 
8849 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
8850 @*/
8851 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
8852 {
8853   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
8854   void    **ctxs;
8855   PetscReal time;
8856   PetscInt  Nf, f, Nds, s;
8857 
8858   PetscFunctionBegin;
8859   PetscCall(DMGetNumFields(dm, &Nf));
8860   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
8861   PetscCall(DMGetNumDS(dm, &Nds));
8862   for (s = 0; s < Nds; ++s) {
8863     PetscDS         ds;
8864     DMLabel         label;
8865     IS              fieldIS;
8866     const PetscInt *fields;
8867     PetscInt        dsNf;
8868 
8869     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
8870     PetscCall(PetscDSGetNumFields(ds, &dsNf));
8871     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
8872     for (f = 0; f < dsNf; ++f) {
8873       const PetscInt field = fields[f];
8874       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
8875     }
8876     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
8877   }
8878   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);
8879   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
8880   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
8881   if (errorVec) {
8882     DM             edm;
8883     DMPolytopeType ct;
8884     PetscBool      simplex;
8885     PetscInt       dim, cStart, Nf;
8886 
8887     PetscCall(DMClone(dm, &edm));
8888     PetscCall(DMGetDimension(edm, &dim));
8889     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
8890     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8891     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
8892     PetscCall(DMGetNumFields(dm, &Nf));
8893     for (f = 0; f < Nf; ++f) {
8894       PetscFE         fe, efe;
8895       PetscQuadrature q;
8896       const char     *name;
8897 
8898       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
8899       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
8900       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
8901       PetscCall(PetscObjectSetName((PetscObject)efe, name));
8902       PetscCall(PetscFEGetQuadrature(fe, &q));
8903       PetscCall(PetscFESetQuadrature(efe, q));
8904       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
8905       PetscCall(PetscFEDestroy(&efe));
8906     }
8907     PetscCall(DMCreateDS(edm));
8908 
8909     PetscCall(DMCreateGlobalVector(edm, errorVec));
8910     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
8911     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
8912     PetscCall(DMDestroy(&edm));
8913   }
8914   PetscCall(PetscFree2(exactSol, ctxs));
8915   PetscFunctionReturn(PETSC_SUCCESS);
8916 }
8917 
8918 /*@
8919   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
8920 
8921   Not Collective
8922 
8923   Input Parameter:
8924 . dm - The `DM`
8925 
8926   Output Parameter:
8927 . numAux - The number of auxiliary data vectors
8928 
8929   Level: advanced
8930 
8931 .seealso: [](ch_dmbase), `DM`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`
8932 @*/
8933 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
8934 {
8935   PetscFunctionBegin;
8936   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8937   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
8938   PetscFunctionReturn(PETSC_SUCCESS);
8939 }
8940 
8941 /*@
8942   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
8943 
8944   Not Collective
8945 
8946   Input Parameters:
8947 + dm    - The `DM`
8948 . label - The `DMLabel`
8949 . value - The label value indicating the region
8950 - part  - The equation part, or 0 if unused
8951 
8952   Output Parameter:
8953 . aux - The `Vec` holding auxiliary field data
8954 
8955   Level: advanced
8956 
8957   Note:
8958   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
8959 
8960 .seealso: [](ch_dmbase), `DM`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
8961 @*/
8962 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
8963 {
8964   PetscHashAuxKey key, wild = {NULL, 0, 0};
8965   PetscBool       has;
8966 
8967   PetscFunctionBegin;
8968   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8969   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
8970   key.label = label;
8971   key.value = value;
8972   key.part  = part;
8973   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
8974   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
8975   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
8976   PetscFunctionReturn(PETSC_SUCCESS);
8977 }
8978 
8979 /*@
8980   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
8981 
8982   Not Collective because auxiliary vectors are not parallel
8983 
8984   Input Parameters:
8985 + dm    - The `DM`
8986 . label - The `DMLabel`
8987 . value - The label value indicating the region
8988 . part  - The equation part, or 0 if unused
8989 - aux   - The `Vec` holding auxiliary field data
8990 
8991   Level: advanced
8992 
8993 .seealso: [](ch_dmbase), `DM`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
8994 @*/
8995 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
8996 {
8997   Vec             old;
8998   PetscHashAuxKey key;
8999 
9000   PetscFunctionBegin;
9001   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9002   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9003   key.label = label;
9004   key.value = value;
9005   key.part  = part;
9006   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9007   PetscCall(PetscObjectReference((PetscObject)aux));
9008   PetscCall(PetscObjectDereference((PetscObject)old));
9009   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9010   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9011   PetscFunctionReturn(PETSC_SUCCESS);
9012 }
9013 
9014 /*@C
9015   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9016 
9017   Not Collective
9018 
9019   Input Parameter:
9020 . dm - The `DM`
9021 
9022   Output Parameters:
9023 + labels - The `DMLabel`s for each `Vec`
9024 . values - The label values for each `Vec`
9025 - parts  - The equation parts for each `Vec`
9026 
9027   Level: advanced
9028 
9029   Note:
9030   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9031 
9032 .seealso: [](ch_dmbase), `DM`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()`
9033 @*/
9034 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9035 {
9036   PetscHashAuxKey *keys;
9037   PetscInt         n, i, off = 0;
9038 
9039   PetscFunctionBegin;
9040   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9041   PetscAssertPointer(labels, 2);
9042   PetscAssertPointer(values, 3);
9043   PetscAssertPointer(parts, 4);
9044   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9045   PetscCall(PetscMalloc1(n, &keys));
9046   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9047   for (i = 0; i < n; ++i) {
9048     labels[i] = keys[i].label;
9049     values[i] = keys[i].value;
9050     parts[i]  = keys[i].part;
9051   }
9052   PetscCall(PetscFree(keys));
9053   PetscFunctionReturn(PETSC_SUCCESS);
9054 }
9055 
9056 /*@
9057   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9058 
9059   Not Collective
9060 
9061   Input Parameter:
9062 . dm - The `DM`
9063 
9064   Output Parameter:
9065 . dmNew - The new `DM`, now with the same auxiliary data
9066 
9067   Level: advanced
9068 
9069   Note:
9070   This is a shallow copy of the auxiliary vectors
9071 
9072 .seealso: [](ch_dmbase), `DM`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9073 @*/
9074 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9075 {
9076   PetscFunctionBegin;
9077   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9078   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9079   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9080   PetscFunctionReturn(PETSC_SUCCESS);
9081 }
9082 
9083 /*@C
9084   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9085 
9086   Not Collective
9087 
9088   Input Parameters:
9089 + ct         - The `DMPolytopeType`
9090 . sourceCone - The source arrangement of faces
9091 - targetCone - The target arrangement of faces
9092 
9093   Output Parameters:
9094 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9095 - found - Flag indicating that a suitable orientation was found
9096 
9097   Level: advanced
9098 
9099   Note:
9100   An arrangement is a face order combined with an orientation for each face
9101 
9102   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
9103   that labels each arrangement (face ordering plus orientation for each face).
9104 
9105   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9106 
9107 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9108 @*/
9109 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9110 {
9111   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9112   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
9113   PetscInt       o, c;
9114 
9115   PetscFunctionBegin;
9116   if (!nO) {
9117     *ornt  = 0;
9118     *found = PETSC_TRUE;
9119     PetscFunctionReturn(PETSC_SUCCESS);
9120   }
9121   for (o = -nO; o < nO; ++o) {
9122     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
9123 
9124     for (c = 0; c < cS; ++c)
9125       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9126     if (c == cS) {
9127       *ornt = o;
9128       break;
9129     }
9130   }
9131   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9132   PetscFunctionReturn(PETSC_SUCCESS);
9133 }
9134 
9135 /*@C
9136   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9137 
9138   Not Collective
9139 
9140   Input Parameters:
9141 + ct         - The `DMPolytopeType`
9142 . sourceCone - The source arrangement of faces
9143 - targetCone - The target arrangement of faces
9144 
9145   Output Parameter:
9146 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9147 
9148   Level: advanced
9149 
9150   Note:
9151   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9152 
9153   Developer Notes:
9154   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9155 
9156 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9157 @*/
9158 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9159 {
9160   PetscBool found;
9161 
9162   PetscFunctionBegin;
9163   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9164   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9165   PetscFunctionReturn(PETSC_SUCCESS);
9166 }
9167 
9168 /*@C
9169   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9170 
9171   Not Collective
9172 
9173   Input Parameters:
9174 + ct         - The `DMPolytopeType`
9175 . sourceVert - The source arrangement of vertices
9176 - targetVert - The target arrangement of vertices
9177 
9178   Output Parameters:
9179 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9180 - found - Flag indicating that a suitable orientation was found
9181 
9182   Level: advanced
9183 
9184   Note:
9185   An arrangement is a vertex order
9186 
9187   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
9188   that labels each arrangement (vertex ordering).
9189 
9190   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9191 
9192 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()`
9193 @*/
9194 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9195 {
9196   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9197   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
9198   PetscInt       o, c;
9199 
9200   PetscFunctionBegin;
9201   if (!nO) {
9202     *ornt  = 0;
9203     *found = PETSC_TRUE;
9204     PetscFunctionReturn(PETSC_SUCCESS);
9205   }
9206   for (o = -nO; o < nO; ++o) {
9207     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
9208 
9209     for (c = 0; c < cS; ++c)
9210       if (sourceVert[arr[c]] != targetVert[c]) break;
9211     if (c == cS) {
9212       *ornt = o;
9213       break;
9214     }
9215   }
9216   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9217   PetscFunctionReturn(PETSC_SUCCESS);
9218 }
9219 
9220 /*@C
9221   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9222 
9223   Not Collective
9224 
9225   Input Parameters:
9226 + ct         - The `DMPolytopeType`
9227 . sourceCone - The source arrangement of vertices
9228 - targetCone - The target arrangement of vertices
9229 
9230   Output Parameter:
9231 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement
9232 
9233   Level: advanced
9234 
9235   Note:
9236   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9237 
9238   Developer Notes:
9239   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9240 
9241 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9242 @*/
9243 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9244 {
9245   PetscBool found;
9246 
9247   PetscFunctionBegin;
9248   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9249   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9250   PetscFunctionReturn(PETSC_SUCCESS);
9251 }
9252 
9253 /*@C
9254   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9255 
9256   Not Collective
9257 
9258   Input Parameters:
9259 + ct    - The `DMPolytopeType`
9260 - point - Coordinates of the point
9261 
9262   Output Parameter:
9263 . inside - Flag indicating whether the point is inside the reference cell of given type
9264 
9265   Level: advanced
9266 
9267 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()`
9268 @*/
9269 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9270 {
9271   PetscReal sum = 0.0;
9272   PetscInt  d;
9273 
9274   PetscFunctionBegin;
9275   *inside = PETSC_TRUE;
9276   switch (ct) {
9277   case DM_POLYTOPE_TRIANGLE:
9278   case DM_POLYTOPE_TETRAHEDRON:
9279     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9280       if (point[d] < -1.0) {
9281         *inside = PETSC_FALSE;
9282         break;
9283       }
9284       sum += point[d];
9285     }
9286     if (sum > PETSC_SMALL) {
9287       *inside = PETSC_FALSE;
9288       break;
9289     }
9290     break;
9291   case DM_POLYTOPE_QUADRILATERAL:
9292   case DM_POLYTOPE_HEXAHEDRON:
9293     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9294       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9295         *inside = PETSC_FALSE;
9296         break;
9297       }
9298     break;
9299   default:
9300     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9301   }
9302   PetscFunctionReturn(PETSC_SUCCESS);
9303 }
9304