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