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