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