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