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