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