xref: /petsc/src/dm/interface/dm.c (revision ab4ee011827fbbb77f789779c813f6db6bb0cbfa)
1 #include <petscvec.h>
2 #include <petsc/private/dmimpl.h>      /*I      "petscdm.h"          I*/
3 #include <petsc/private/dmlabelimpl.h> /*I      "petscdmlabel.h"     I*/
4 #include <petsc/private/petscdsimpl.h> /*I      "petscds.h"     I*/
5 #include <petscdmplex.h>
6 #include <petscdmfield.h>
7 #include <petscsf.h>
8 #include <petscds.h>
9 
10 #ifdef PETSC_HAVE_LIBCEED
11   #include <petscfeceed.h>
12 #endif
13 
14 #if !defined(PETSC_HAVE_WINDOWS_COMPILERS)
15   #include <petsc/private/valgrind/memcheck.h>
16 #endif
17 
18 PetscClassId DM_CLASSID;
19 PetscClassId DMLABEL_CLASSID;
20 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal, DM_LocatePoints, DM_Coarsen, DM_Refine, DM_CreateInterpolation, DM_CreateRestriction, DM_CreateInjection, DM_CreateMatrix, DM_CreateMassMatrix, DM_Load, DM_AdaptInterpolator, DM_ProjectFunction;
21 
22 const char *const DMBoundaryTypes[]          = {"NONE", "GHOSTED", "MIRROR", "PERIODIC", "TWIST", "DMBoundaryType", "DM_BOUNDARY_", NULL};
23 const char *const DMBoundaryConditionTypes[] = {"INVALID", "ESSENTIAL", "NATURAL", "INVALID", "INVALID", "ESSENTIAL_FIELD", "NATURAL_FIELD", "INVALID", "INVALID", "ESSENTIAL_BD_FIELD", "NATURAL_RIEMANN", "DMBoundaryConditionType", "DM_BC_", NULL};
24 const char *const DMBlockingTypes[]          = {"TOPOLOGICAL_POINT", "FIELD_NODE", "DMBlockingType", "DM_BLOCKING_", NULL};
25 const char *const DMPolytopeTypes[]   = {"vertex",  "segment",       "tensor_segment",      "triangle", "quadrilateral", "tensor_quad",    "tetrahedron",  "hexahedron", "triangular_prism", "tensor_triangular_prism", "tensor_quadrilateral_prism",
26                                          "pyramid", "FV_ghost_cell", "interior_ghost_cell", "unknown",  "invalid",       "DMPolytopeType", "DM_POLYTOPE_", NULL};
27 const char *const DMCopyLabelsModes[] = {"replace", "keep", "fail", "DMCopyLabelsMode", "DM_COPY_LABELS_", NULL};
28 
29 /*@
30   DMCreate - Creates an empty `DM` object. `DM`s are the abstract objects in PETSc that mediate between meshes and discretizations and the
31   algebraic solvers, time integrators, and optimization algorithms.
32 
33   Collective
34 
35   Input Parameter:
36 . comm - The communicator for the `DM` object
37 
38   Output Parameter:
39 . dm - The `DM` object
40 
41   Level: beginner
42 
43   Notes:
44   See `DMType` for a brief summary of available `DM`.
45 
46   The type must then be set with `DMSetType()`. If you never call `DMSetType()` it will generate an
47   error when you try to use the dm.
48 
49 .seealso: `DMSetType()`, `DMType`, `DMDACreate()`, `DMDA`, `DMSLICED`, `DMCOMPOSITE`, `DMPLEX`, `DMMOAB`, `DMNETWORK`
50 @*/
51 PetscErrorCode DMCreate(MPI_Comm comm, DM *dm)
52 {
53   DM      v;
54   PetscDS ds;
55 
56   PetscFunctionBegin;
57   PetscValidPointer(dm, 2);
58   *dm = NULL;
59   PetscCall(DMInitializePackage());
60 
61   PetscCall(PetscHeaderCreate(v, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView));
62 
63   ((PetscObject)v)->non_cyclic_references = &DMCountNonCyclicReferences;
64 
65   v->setupcalled          = PETSC_FALSE;
66   v->setfromoptionscalled = PETSC_FALSE;
67   v->ltogmap              = NULL;
68   v->bind_below           = 0;
69   v->bs                   = 1;
70   v->coloringtype         = IS_COLORING_GLOBAL;
71   PetscCall(PetscSFCreate(comm, &v->sf));
72   PetscCall(PetscSFCreate(comm, &v->sectionSF));
73   v->labels                    = NULL;
74   v->adjacency[0]              = PETSC_FALSE;
75   v->adjacency[1]              = PETSC_TRUE;
76   v->depthLabel                = NULL;
77   v->celltypeLabel             = NULL;
78   v->localSection              = NULL;
79   v->globalSection             = NULL;
80   v->defaultConstraint.section = NULL;
81   v->defaultConstraint.mat     = NULL;
82   v->defaultConstraint.bias    = NULL;
83   v->coordinates[0].dim        = PETSC_DEFAULT;
84   v->coordinates[1].dim        = PETSC_DEFAULT;
85   v->sparseLocalize            = PETSC_TRUE;
86   v->dim                       = PETSC_DETERMINE;
87   {
88     PetscInt i;
89     for (i = 0; i < 10; ++i) {
90       v->nullspaceConstructors[i]     = NULL;
91       v->nearnullspaceConstructors[i] = NULL;
92     }
93   }
94   PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
95   PetscCall(DMSetRegionDS(v, NULL, NULL, ds, NULL));
96   PetscCall(PetscDSDestroy(&ds));
97   PetscCall(PetscHMapAuxCreate(&v->auxData));
98   v->dmBC              = NULL;
99   v->coarseMesh        = NULL;
100   v->outputSequenceNum = -1;
101   v->outputSequenceVal = 0.0;
102   PetscCall(DMSetVecType(v, VECSTANDARD));
103   PetscCall(DMSetMatType(v, MATAIJ));
104 
105   *dm = v;
106   PetscFunctionReturn(PETSC_SUCCESS);
107 }
108 
109 /*@
110   DMClone - Creates a `DM` object with the same topology as the original.
111 
112   Collective
113 
114   Input Parameter:
115 . dm - The original `DM` object
116 
117   Output Parameter:
118 . newdm  - The new `DM` object
119 
120   Level: beginner
121 
122   Notes:
123   For some `DM` implementations this is a shallow clone, the result of which may share (reference counted) information with its parent. For example,
124   `DMClone()` applied to a `DMPLEX` object will result in a new `DMPLEX` that shares the topology with the original `DMPLEX`. It does not
125   share the `PetscSection` of the original `DM`.
126 
127   The clone is considered set up if the original has been set up.
128 
129   Use `DMConvert()` for a general way to create new `DM` from a given `DM`
130 
131 .seealso: `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 Parameter:
533 .  dm - the `DM` context
534 
535    Output Parameter:
536 .  prefix - pointer to the prefix string used is returned
537 
538    Level: advanced
539 
540    Fortran Note:
541    Pass in a string 'prefix' of
542    sufficient length to hold the prefix.
543 
544 .seealso: `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 Parameter:
1609 . dm - the `DM`
1610 
1611   Output Parameter:
1612 . btype - block by topological point or field node
1613 
1614   Level: advanced
1615 
1616 .seealso: `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, NULL));
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, NULL));
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(PetscDSDestroy(&dm->probs[s].dsIn));
5390     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5391     PetscCall(ISDestroy(&dm->probs[s].fields));
5392   }
5393   PetscCall(PetscFree(dm->probs));
5394   dm->probs = NULL;
5395   dm->Nds   = 0;
5396   PetscFunctionReturn(PETSC_SUCCESS);
5397 }
5398 
5399 /*@
5400   DMGetDS - Get the default `PetscDS`
5401 
5402   Not Collective
5403 
5404   Input Parameter:
5405 . dm - The `DM`
5406 
5407   Output Parameter:
5408 . ds - The default `PetscDS`
5409 
5410   Level: intermediate
5411 
5412 .seealso: `DMGetCellDS()`, `DMGetRegionDS()`
5413 @*/
5414 PetscErrorCode DMGetDS(DM dm, PetscDS *ds)
5415 {
5416   PetscFunctionBeginHot;
5417   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5418   PetscValidPointer(ds, 2);
5419   PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()");
5420   *ds = dm->probs[0].ds;
5421   PetscFunctionReturn(PETSC_SUCCESS);
5422 }
5423 
5424 /*@
5425   DMGetCellDS - Get the `PetscDS` defined on a given cell
5426 
5427   Not Collective
5428 
5429   Input Parameters:
5430 + dm    - The `DM`
5431 - point - Cell for the `PetscDS`
5432 
5433   Output Parameters:
5434 + ds   - The `PetscDS` defined on the given cell
5435 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds
5436 
5437   Level: developer
5438 
5439 .seealso: `DMGetDS()`, `DMSetRegionDS()`
5440 @*/
5441 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn)
5442 {
5443   PetscDS  dsDef = NULL;
5444   PetscInt s;
5445 
5446   PetscFunctionBeginHot;
5447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5448   if (ds) PetscValidPointer(ds, 3);
5449   if (dsIn) PetscValidPointer(dsIn, 4);
5450   PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5451   if (ds) *ds = NULL;
5452   if (dsIn) *dsIn = NULL;
5453   for (s = 0; s < dm->Nds; ++s) {
5454     PetscInt val;
5455 
5456     if (!dm->probs[s].label) {
5457       dsDef = dm->probs[s].ds;
5458     } else {
5459       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5460       if (val >= 0) {
5461         if (ds) *ds = dm->probs[s].ds;
5462         if (dsIn) *dsIn = dm->probs[s].dsIn;
5463         break;
5464       }
5465     }
5466   }
5467   if (ds && !*ds) *ds = dsDef;
5468   PetscFunctionReturn(PETSC_SUCCESS);
5469 }
5470 
5471 /*@
5472   DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel`
5473 
5474   Not Collective
5475 
5476   Input Parameters:
5477 + dm    - The `DM`
5478 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5479 
5480   Output Parameters:
5481 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5482 . ds     - The `PetscDS` defined on the given region, or `NULL`
5483 - dsIn   - The `PetscDS` for input in 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 ds = `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, PetscDS *dsIn)
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   if (dsIn) {
5510     PetscValidPointer(dsIn, 5);
5511     *dsIn = NULL;
5512   }
5513   for (s = 0; s < Nds; ++s) {
5514     if (dm->probs[s].label == label || !dm->probs[s].label) {
5515       if (fields) *fields = dm->probs[s].fields;
5516       if (ds) *ds = dm->probs[s].ds;
5517       if (dsIn) *dsIn = dm->probs[s].dsIn;
5518       if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS);
5519     }
5520   }
5521   PetscFunctionReturn(PETSC_SUCCESS);
5522 }
5523 
5524 /*@
5525   DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel`
5526 
5527   Collective
5528 
5529   Input Parameters:
5530 + dm     - The `DM`
5531 . label  - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh
5532 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields
5533 . ds     - The `PetscDS` defined on the given region
5534 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5535 
5536   Level: advanced
5537 
5538   Note:
5539   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced,
5540   the fields argument is ignored.
5541 
5542 .seealso: `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5543 @*/
5544 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5545 {
5546   PetscInt Nds = dm->Nds, s;
5547 
5548   PetscFunctionBegin;
5549   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5550   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5551   if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3);
5552   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5553   if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5);
5554   for (s = 0; s < Nds; ++s) {
5555     if (dm->probs[s].label == label) {
5556       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5557       PetscCall(PetscDSDestroy(&dm->probs[s].dsIn));
5558       dm->probs[s].ds   = ds;
5559       dm->probs[s].dsIn = dsIn;
5560       PetscFunctionReturn(PETSC_SUCCESS);
5561     }
5562   }
5563   PetscCall(DMDSEnlarge_Static(dm, Nds + 1));
5564   PetscCall(PetscObjectReference((PetscObject)label));
5565   PetscCall(PetscObjectReference((PetscObject)fields));
5566   PetscCall(PetscObjectReference((PetscObject)ds));
5567   PetscCall(PetscObjectReference((PetscObject)dsIn));
5568   if (!label) {
5569     /* Put the NULL label at the front, so it is returned as the default */
5570     for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s];
5571     Nds = 0;
5572   }
5573   dm->probs[Nds].label  = label;
5574   dm->probs[Nds].fields = fields;
5575   dm->probs[Nds].ds     = ds;
5576   dm->probs[Nds].dsIn   = dsIn;
5577   PetscFunctionReturn(PETSC_SUCCESS);
5578 }
5579 
5580 /*@
5581   DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number
5582 
5583   Not Collective
5584 
5585   Input Parameters:
5586 + dm  - The `DM`
5587 - num - The region number, in [0, Nds)
5588 
5589   Output Parameters:
5590 + label  - The region label, or `NULL`
5591 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL`
5592 . ds     - The `PetscDS` defined on the given region, or `NULL`
5593 - dsIn   - The `PetscDS` for input in the given region, or `NULL`
5594 
5595   Level: advanced
5596 
5597 .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5598 @*/
5599 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn)
5600 {
5601   PetscInt Nds;
5602 
5603   PetscFunctionBegin;
5604   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5605   PetscCall(DMGetNumDS(dm, &Nds));
5606   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5607   if (label) {
5608     PetscValidPointer(label, 3);
5609     *label = dm->probs[num].label;
5610   }
5611   if (fields) {
5612     PetscValidPointer(fields, 4);
5613     *fields = dm->probs[num].fields;
5614   }
5615   if (ds) {
5616     PetscValidPointer(ds, 5);
5617     *ds = dm->probs[num].ds;
5618   }
5619   if (dsIn) {
5620     PetscValidPointer(dsIn, 6);
5621     *dsIn = dm->probs[num].dsIn;
5622   }
5623   PetscFunctionReturn(PETSC_SUCCESS);
5624 }
5625 
5626 /*@
5627   DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number
5628 
5629   Not Collective
5630 
5631   Input Parameters:
5632 + dm     - The `DM`
5633 . num    - The region number, in [0, Nds)
5634 . label  - The region label, or `NULL`
5635 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting
5636 . ds     - The `PetscDS` defined on the given region, or `NULL` to prevent setting
5637 - dsIn   - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS`
5638 
5639   Level: advanced
5640 
5641 .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5642 @*/
5643 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
5644 {
5645   PetscInt Nds;
5646 
5647   PetscFunctionBegin;
5648   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5649   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
5650   PetscCall(DMGetNumDS(dm, &Nds));
5651   PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5652   PetscCall(PetscObjectReference((PetscObject)label));
5653   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5654   dm->probs[num].label = label;
5655   if (fields) {
5656     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5657     PetscCall(PetscObjectReference((PetscObject)fields));
5658     PetscCall(ISDestroy(&dm->probs[num].fields));
5659     dm->probs[num].fields = fields;
5660   }
5661   if (ds) {
5662     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5663     PetscCall(PetscObjectReference((PetscObject)ds));
5664     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5665     dm->probs[num].ds = ds;
5666   }
5667   if (dsIn) {
5668     PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6);
5669     PetscCall(PetscObjectReference((PetscObject)dsIn));
5670     PetscCall(PetscDSDestroy(&dm->probs[num].dsIn));
5671     dm->probs[num].dsIn = dsIn;
5672   }
5673   PetscFunctionReturn(PETSC_SUCCESS);
5674 }
5675 
5676 /*@
5677   DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found.
5678 
5679   Not Collective
5680 
5681   Input Parameters:
5682 + dm  - The `DM`
5683 - ds  - The `PetscDS` defined on the given region
5684 
5685   Output Parameter:
5686 . num - The region number, in [0, Nds), or -1 if not found
5687 
5688   Level: advanced
5689 
5690 .seealso: `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5691 @*/
5692 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5693 {
5694   PetscInt Nds, n;
5695 
5696   PetscFunctionBegin;
5697   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5698   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5699   PetscValidIntPointer(num, 3);
5700   PetscCall(DMGetNumDS(dm, &Nds));
5701   for (n = 0; n < Nds; ++n)
5702     if (ds == dm->probs[n].ds) break;
5703   if (n >= Nds) *num = -1;
5704   else *num = n;
5705   PetscFunctionReturn(PETSC_SUCCESS);
5706 }
5707 
5708 /*@C
5709   DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh
5710 
5711   Not Collective
5712 
5713   Input Parameters:
5714 + dm     - The `DM`
5715 . Nc     - The number of components for the field
5716 . prefix - The options prefix for the output `PetscFE`, or `NULL`
5717 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree
5718 
5719   Output Parameter:
5720 . fem - The `PetscFE`
5721 
5722   Level: intermediate
5723 
5724   Note:
5725   This is a convenience method that just calls `PetscFECreateByCell()` underneath.
5726 
5727 .seealso: `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5728 @*/
5729 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5730 {
5731   DMPolytopeType ct;
5732   PetscInt       dim, cStart;
5733 
5734   PetscFunctionBegin;
5735   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5736   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5737   if (prefix) PetscValidCharPointer(prefix, 3);
5738   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5739   PetscValidPointer(fem, 5);
5740   PetscCall(DMGetDimension(dm, &dim));
5741   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5742   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5743   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5744   PetscFunctionReturn(PETSC_SUCCESS);
5745 }
5746 
5747 /*@
5748   DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM`
5749 
5750   Collective
5751 
5752   Input Parameter:
5753 . dm - The `DM`
5754 
5755   Options Database Key:
5756 . -dm_petscds_view - View all the `PetscDS` objects in this `DM`
5757 
5758   Level: intermediate
5759 
5760   Note:
5761   If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`.
5762 
5763 .seealso: `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5764 @*/
5765 PetscErrorCode DMCreateDS(DM dm)
5766 {
5767   MPI_Comm  comm;
5768   PetscDS   dsDef;
5769   DMLabel  *labelSet;
5770   PetscInt  dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5771   PetscBool doSetup = PETSC_TRUE, flg;
5772 
5773   PetscFunctionBegin;
5774   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5775   if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS);
5776   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
5777   PetscCall(DMGetCoordinateDim(dm, &dE));
5778   /* Determine how many regions we have */
5779   PetscCall(PetscMalloc1(Nf, &labelSet));
5780   Nl   = 0;
5781   Ndef = 0;
5782   for (f = 0; f < Nf; ++f) {
5783     DMLabel  label = dm->fields[f].label;
5784     PetscInt l;
5785 
5786 #ifdef PETSC_HAVE_LIBCEED
5787     /* Move CEED context to discretizations */
5788     {
5789       PetscClassId id;
5790 
5791       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5792       if (id == PETSCFE_CLASSID) {
5793         Ceed ceed;
5794 
5795         PetscCall(DMGetCeed(dm, &ceed));
5796         PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed));
5797       }
5798     }
5799 #endif
5800     if (!label) {
5801       ++Ndef;
5802       continue;
5803     }
5804     for (l = 0; l < Nl; ++l)
5805       if (label == labelSet[l]) break;
5806     if (l < Nl) continue;
5807     labelSet[Nl++] = label;
5808   }
5809   /* Create default DS if there are no labels to intersect with */
5810   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5811   if (!dsDef && Ndef && !Nl) {
5812     IS        fields;
5813     PetscInt *fld, nf;
5814 
5815     for (f = 0, nf = 0; f < Nf; ++f)
5816       if (!dm->fields[f].label) ++nf;
5817     PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5818     PetscCall(PetscMalloc1(nf, &fld));
5819     for (f = 0, nf = 0; f < Nf; ++f)
5820       if (!dm->fields[f].label) fld[nf++] = f;
5821     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5822     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5823     PetscCall(ISSetType(fields, ISGENERAL));
5824     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5825 
5826     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5827     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL));
5828     PetscCall(PetscDSDestroy(&dsDef));
5829     PetscCall(ISDestroy(&fields));
5830   }
5831   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL));
5832   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5833   /* Intersect labels with default fields */
5834   if (Ndef && Nl) {
5835     DM              plex;
5836     DMLabel         cellLabel;
5837     IS              fieldIS, allcellIS, defcellIS = NULL;
5838     PetscInt       *fields;
5839     const PetscInt *cells;
5840     PetscInt        depth, nf = 0, n, c;
5841 
5842     PetscCall(DMConvert(dm, DMPLEX, &plex));
5843     PetscCall(DMPlexGetDepth(plex, &depth));
5844     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5845     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5846     /* TODO This looks like it only works for one label */
5847     for (l = 0; l < Nl; ++l) {
5848       DMLabel label = labelSet[l];
5849       IS      pointIS;
5850 
5851       PetscCall(ISDestroy(&defcellIS));
5852       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5853       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5854       PetscCall(ISDestroy(&pointIS));
5855     }
5856     PetscCall(ISDestroy(&allcellIS));
5857 
5858     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5859     PetscCall(ISGetLocalSize(defcellIS, &n));
5860     PetscCall(ISGetIndices(defcellIS, &cells));
5861     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5862     PetscCall(ISRestoreIndices(defcellIS, &cells));
5863     PetscCall(ISDestroy(&defcellIS));
5864     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5865 
5866     PetscCall(PetscMalloc1(Ndef, &fields));
5867     for (f = 0; f < Nf; ++f)
5868       if (!dm->fields[f].label) fields[nf++] = f;
5869     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
5870     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_"));
5871     PetscCall(ISSetType(fieldIS, ISGENERAL));
5872     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
5873 
5874     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5875     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL));
5876     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5877     PetscCall(DMLabelDestroy(&cellLabel));
5878     PetscCall(PetscDSDestroy(&dsDef));
5879     PetscCall(ISDestroy(&fieldIS));
5880     PetscCall(DMDestroy(&plex));
5881   }
5882   /* Create label DSes
5883      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5884   */
5885   /* TODO Should check that labels are disjoint */
5886   for (l = 0; l < Nl; ++l) {
5887     DMLabel   label = labelSet[l];
5888     PetscDS   ds, dsIn = NULL;
5889     IS        fields;
5890     PetscInt *fld, nf;
5891 
5892     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
5893     for (f = 0, nf = 0; f < Nf; ++f)
5894       if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5895     PetscCall(PetscMalloc1(nf, &fld));
5896     for (f = 0, nf = 0; f < Nf; ++f)
5897       if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5898     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5899     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_"));
5900     PetscCall(ISSetType(fields, ISGENERAL));
5901     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5902     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
5903     {
5904       DMPolytopeType ct;
5905       PetscInt       lStart, lEnd;
5906       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
5907 
5908       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
5909       if (lStart >= 0) {
5910         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
5911         switch (ct) {
5912         case DM_POLYTOPE_POINT_PRISM_TENSOR:
5913         case DM_POLYTOPE_SEG_PRISM_TENSOR:
5914         case DM_POLYTOPE_TRI_PRISM_TENSOR:
5915         case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5916           isCohesiveLocal = PETSC_TRUE;
5917           break;
5918         default:
5919           break;
5920         }
5921       }
5922       PetscCallMPI(MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
5923       if (isCohesive) {
5924         PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn));
5925         PetscCall(PetscDSSetCoordinateDimension(dsIn, dE));
5926       }
5927       for (f = 0, nf = 0; f < Nf; ++f) {
5928         if (label == dm->fields[f].label || !dm->fields[f].label) {
5929           if (label == dm->fields[f].label) {
5930             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
5931             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
5932             if (dsIn) {
5933               PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL));
5934               PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive));
5935             }
5936           }
5937           ++nf;
5938         }
5939       }
5940     }
5941     PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn));
5942     PetscCall(ISDestroy(&fields));
5943     PetscCall(PetscDSDestroy(&ds));
5944     PetscCall(PetscDSDestroy(&dsIn));
5945   }
5946   PetscCall(PetscFree(labelSet));
5947   /* Set fields in DSes */
5948   for (s = 0; s < dm->Nds; ++s) {
5949     PetscDS         ds     = dm->probs[s].ds;
5950     PetscDS         dsIn   = dm->probs[s].dsIn;
5951     IS              fields = dm->probs[s].fields;
5952     const PetscInt *fld;
5953     PetscInt        nf, dsnf;
5954     PetscBool       isCohesive;
5955 
5956     PetscCall(PetscDSGetNumFields(ds, &dsnf));
5957     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
5958     PetscCall(ISGetLocalSize(fields, &nf));
5959     PetscCall(ISGetIndices(fields, &fld));
5960     for (f = 0; f < nf; ++f) {
5961       PetscObject  disc = dm->fields[fld[f]].disc;
5962       PetscBool    isCohesiveField;
5963       PetscClassId id;
5964 
5965       /* Handle DS with no fields */
5966       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
5967       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5968       if (isCohesive) {
5969         if (!isCohesiveField) {
5970           PetscObject bdDisc;
5971 
5972           PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc));
5973           PetscCall(PetscDSSetDiscretization(ds, f, bdDisc));
5974           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
5975         } else {
5976           PetscCall(PetscDSSetDiscretization(ds, f, disc));
5977           PetscCall(PetscDSSetDiscretization(dsIn, f, disc));
5978         }
5979       } else {
5980         PetscCall(PetscDSSetDiscretization(ds, f, disc));
5981       }
5982       /* We allow people to have placeholder fields and construct the Section by hand */
5983       PetscCall(PetscObjectGetClassId(disc, &id));
5984       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5985     }
5986     PetscCall(ISRestoreIndices(fields, &fld));
5987   }
5988   /* Allow k-jet tabulation */
5989   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
5990   if (flg) {
5991     for (s = 0; s < dm->Nds; ++s) {
5992       PetscDS  ds   = dm->probs[s].ds;
5993       PetscDS  dsIn = dm->probs[s].dsIn;
5994       PetscInt Nf, f;
5995 
5996       PetscCall(PetscDSGetNumFields(ds, &Nf));
5997       for (f = 0; f < Nf; ++f) {
5998         PetscCall(PetscDSSetJetDegree(ds, f, k));
5999         if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k));
6000       }
6001     }
6002   }
6003   /* Setup DSes */
6004   if (doSetup) {
6005     for (s = 0; s < dm->Nds; ++s) {
6006       PetscCall(PetscDSSetUp(dm->probs[s].ds));
6007       if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn));
6008     }
6009   }
6010   PetscFunctionReturn(PETSC_SUCCESS);
6011 }
6012 
6013 /*@
6014   DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information.
6015 
6016   Collective
6017 
6018   Input Parameters:
6019 + dm   - The `DM`
6020 - time - The time
6021 
6022   Output Parameters:
6023 + u    - The vector will be filled with exact solution values, or `NULL`
6024 - u_t  - The vector will be filled with the time derivative of exact solution values, or `NULL`
6025 
6026   Level: developer
6027 
6028   Note:
6029   The user must call `PetscDSSetExactSolution()` before using this routine
6030 
6031 .seealso: `PetscDSSetExactSolution()`
6032 @*/
6033 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
6034 {
6035   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
6036   void   **ectxs;
6037   Vec      locu, locu_t;
6038   PetscInt Nf, Nds, s;
6039 
6040   PetscFunctionBegin;
6041   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6042   if (u) {
6043     PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
6044     PetscCall(DMGetLocalVector(dm, &locu));
6045     PetscCall(VecSet(locu, 0.));
6046   }
6047   if (u_t) {
6048     PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
6049     PetscCall(DMGetLocalVector(dm, &locu_t));
6050     PetscCall(VecSet(locu_t, 0.));
6051   }
6052   PetscCall(DMGetNumFields(dm, &Nf));
6053   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
6054   PetscCall(DMGetNumDS(dm, &Nds));
6055   for (s = 0; s < Nds; ++s) {
6056     PetscDS         ds;
6057     DMLabel         label;
6058     IS              fieldIS;
6059     const PetscInt *fields, id = 1;
6060     PetscInt        dsNf, f;
6061 
6062     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
6063     PetscCall(PetscDSGetNumFields(ds, &dsNf));
6064     PetscCall(ISGetIndices(fieldIS, &fields));
6065     PetscCall(PetscArrayzero(exacts, Nf));
6066     PetscCall(PetscArrayzero(ectxs, Nf));
6067     if (u) {
6068       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6069       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu));
6070       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu));
6071     }
6072     if (u_t) {
6073       PetscCall(PetscArrayzero(exacts, Nf));
6074       PetscCall(PetscArrayzero(ectxs, Nf));
6075       for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]]));
6076       if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6077       else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t));
6078     }
6079     PetscCall(ISRestoreIndices(fieldIS, &fields));
6080   }
6081   if (u) {
6082     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution"));
6083     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_"));
6084   }
6085   if (u_t) {
6086     PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative"));
6087     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_"));
6088   }
6089   PetscCall(PetscFree2(exacts, ectxs));
6090   if (u) {
6091     PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u));
6092     PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u));
6093     PetscCall(DMRestoreLocalVector(dm, &locu));
6094   }
6095   if (u_t) {
6096     PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t));
6097     PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t));
6098     PetscCall(DMRestoreLocalVector(dm, &locu_t));
6099   }
6100   PetscFunctionReturn(PETSC_SUCCESS);
6101 }
6102 
6103 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn)
6104 {
6105   PetscDS dsNew, dsInNew = NULL;
6106 
6107   PetscFunctionBegin;
6108   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew));
6109   PetscCall(PetscDSCopy(ds, dm, dsNew));
6110   if (dsIn) {
6111     PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew));
6112     PetscCall(PetscDSCopy(dsIn, dm, dsInNew));
6113   }
6114   PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew));
6115   PetscCall(PetscDSDestroy(&dsNew));
6116   PetscCall(PetscDSDestroy(&dsInNew));
6117   PetscFunctionReturn(PETSC_SUCCESS);
6118 }
6119 
6120 /*@
6121   DMCopyDS - Copy the discrete systems for the `DM` into another `DM`
6122 
6123   Collective
6124 
6125   Input Parameter:
6126 . dm - The `DM`
6127 
6128   Output Parameter:
6129 . newdm - The `DM`
6130 
6131   Level: advanced
6132 
6133 .seealso: `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6134 @*/
6135 PetscErrorCode DMCopyDS(DM dm, DM newdm)
6136 {
6137   PetscInt Nds, s;
6138 
6139   PetscFunctionBegin;
6140   if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS);
6141   PetscCall(DMGetNumDS(dm, &Nds));
6142   PetscCall(DMClearDS(newdm));
6143   for (s = 0; s < Nds; ++s) {
6144     DMLabel  label;
6145     IS       fields;
6146     PetscDS  ds, dsIn, newds;
6147     PetscInt Nbd, bd;
6148 
6149     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn));
6150     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6151     PetscCall(DMTransferDS_Internal(newdm, label, fields, ds, dsIn));
6152     /* Complete new labels in the new DS */
6153     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL));
6154     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6155     for (bd = 0; bd < Nbd; ++bd) {
6156       PetscWeakForm wf;
6157       DMLabel       label;
6158       PetscInt      field;
6159 
6160       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6161       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6162     }
6163   }
6164   PetscCall(DMCompleteBCLabels_Internal(newdm));
6165   PetscFunctionReturn(PETSC_SUCCESS);
6166 }
6167 
6168 /*@
6169   DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM`
6170 
6171   Collective
6172 
6173   Input Parameter:
6174 . dm - The `DM`
6175 
6176   Output Parameter:
6177 . newdm - The `DM`
6178 
6179   Level: advanced
6180 
6181   Developer Note:
6182   Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation
6183 
6184 .seealso: `DMCopyFields()`, `DMCopyDS()`
6185 @*/
6186 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6187 {
6188   PetscFunctionBegin;
6189   PetscCall(DMCopyFields(dm, newdm));
6190   PetscCall(DMCopyDS(dm, newdm));
6191   PetscFunctionReturn(PETSC_SUCCESS);
6192 }
6193 
6194 /*@
6195   DMGetDimension - Return the topological dimension of the `DM`
6196 
6197   Not Collective
6198 
6199   Input Parameter:
6200 . dm - The `DM`
6201 
6202   Output Parameter:
6203 . dim - The topological dimension
6204 
6205   Level: beginner
6206 
6207 .seealso: `DMSetDimension()`, `DMCreate()`
6208 @*/
6209 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6210 {
6211   PetscFunctionBegin;
6212   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6213   PetscValidIntPointer(dim, 2);
6214   *dim = dm->dim;
6215   PetscFunctionReturn(PETSC_SUCCESS);
6216 }
6217 
6218 /*@
6219   DMSetDimension - Set the topological dimension of the `DM`
6220 
6221   Collective
6222 
6223   Input Parameters:
6224 + dm - The `DM`
6225 - dim - The topological dimension
6226 
6227   Level: beginner
6228 
6229 .seealso: `DMGetDimension()`, `DMCreate()`
6230 @*/
6231 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6232 {
6233   PetscDS  ds;
6234   PetscInt Nds, n;
6235 
6236   PetscFunctionBegin;
6237   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6238   PetscValidLogicalCollectiveInt(dm, dim, 2);
6239   dm->dim = dim;
6240   if (dm->dim >= 0) {
6241     PetscCall(DMGetNumDS(dm, &Nds));
6242     for (n = 0; n < Nds; ++n) {
6243       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL));
6244       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6245     }
6246   }
6247   PetscFunctionReturn(PETSC_SUCCESS);
6248 }
6249 
6250 /*@
6251   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6252 
6253   Collective
6254 
6255   Input Parameters:
6256 + dm - the `DM`
6257 - dim - the dimension
6258 
6259   Output Parameters:
6260 + pStart - The first point of the given dimension
6261 - pEnd - The first point following points of the given dimension
6262 
6263   Level: intermediate
6264 
6265   Note:
6266   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6267   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6268   then the interval is empty.
6269 
6270 .seealso: `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6271 @*/
6272 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6273 {
6274   PetscInt d;
6275 
6276   PetscFunctionBegin;
6277   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6278   PetscCall(DMGetDimension(dm, &d));
6279   PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6280   PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd);
6281   PetscFunctionReturn(PETSC_SUCCESS);
6282 }
6283 
6284 /*@
6285   DMGetOutputDM - Retrieve the `DM` associated with the layout for output
6286 
6287   Collective
6288 
6289   Input Parameter:
6290 . dm - The original `DM`
6291 
6292   Output Parameter:
6293 . odm - The `DM` which provides the layout for output
6294 
6295   Level: intermediate
6296 
6297   Note:
6298   In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary
6299   conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the
6300   locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof.
6301 
6302 .seealso: `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()`
6303 @*/
6304 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6305 {
6306   PetscSection section;
6307   PetscBool    hasConstraints, ghasConstraints;
6308 
6309   PetscFunctionBegin;
6310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6311   PetscValidPointer(odm, 2);
6312   PetscCall(DMGetLocalSection(dm, &section));
6313   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
6314   PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
6315   if (!ghasConstraints) {
6316     *odm = dm;
6317     PetscFunctionReturn(PETSC_SUCCESS);
6318   }
6319   if (!dm->dmBC) {
6320     PetscSection newSection, gsection;
6321     PetscSF      sf;
6322 
6323     PetscCall(DMClone(dm, &dm->dmBC));
6324     PetscCall(DMCopyDisc(dm, dm->dmBC));
6325     PetscCall(PetscSectionClone(section, &newSection));
6326     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
6327     PetscCall(PetscSectionDestroy(&newSection));
6328     PetscCall(DMGetPointSF(dm->dmBC, &sf));
6329     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
6330     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
6331     PetscCall(PetscSectionDestroy(&gsection));
6332   }
6333   *odm = dm->dmBC;
6334   PetscFunctionReturn(PETSC_SUCCESS);
6335 }
6336 
6337 /*@
6338   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
6339 
6340   Input Parameter:
6341 . dm - The original `DM`
6342 
6343   Output Parameters:
6344 + num - The output sequence number
6345 - val - The output sequence value
6346 
6347   Level: intermediate
6348 
6349   Note:
6350   This is intended for output that should appear in sequence, for instance
6351   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6352 
6353   Developer Note:
6354   The `DM` serves as a convenient place to store the current iteration value. The iteration is not
6355   not directly related to the `DM`.
6356 
6357 .seealso: `VecView()`
6358 @*/
6359 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
6360 {
6361   PetscFunctionBegin;
6362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6363   if (num) {
6364     PetscValidIntPointer(num, 2);
6365     *num = dm->outputSequenceNum;
6366   }
6367   if (val) {
6368     PetscValidRealPointer(val, 3);
6369     *val = dm->outputSequenceVal;
6370   }
6371   PetscFunctionReturn(PETSC_SUCCESS);
6372 }
6373 
6374 /*@
6375   DMSetOutputSequenceNumber - Set the sequence number/value for output
6376 
6377   Input Parameters:
6378 + dm - The original `DM`
6379 . num - The output sequence number
6380 - val - The output sequence value
6381 
6382   Level: intermediate
6383 
6384   Note:
6385   This is intended for output that should appear in sequence, for instance
6386   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6387 
6388 .seealso: `VecView()`
6389 @*/
6390 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
6391 {
6392   PetscFunctionBegin;
6393   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6394   dm->outputSequenceNum = num;
6395   dm->outputSequenceVal = val;
6396   PetscFunctionReturn(PETSC_SUCCESS);
6397 }
6398 
6399 /*@C
6400  DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer`
6401 
6402   Input Parameters:
6403 + dm   - The original `DM`
6404 . name - The sequence name
6405 - num  - The output sequence number
6406 
6407   Output Parameter:
6408 . val  - The output sequence value
6409 
6410   Level: intermediate
6411 
6412   Note:
6413   This is intended for output that should appear in sequence, for instance
6414   a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system.
6415 
6416   Developer Note:
6417   It is unclear at the user API level why a `DM` is needed as input
6418 
6419 .seealso: `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
6420 @*/
6421 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
6422 {
6423   PetscBool ishdf5;
6424 
6425   PetscFunctionBegin;
6426   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6427   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
6428   PetscValidRealPointer(val, 5);
6429   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
6430   if (ishdf5) {
6431 #if defined(PETSC_HAVE_HDF5)
6432     PetscScalar value;
6433 
6434     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
6435     *val = PetscRealPart(value);
6436 #endif
6437   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
6438   PetscFunctionReturn(PETSC_SUCCESS);
6439 }
6440 
6441 /*@
6442   DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6443 
6444   Not Collective
6445 
6446   Input Parameter:
6447 . dm - The `DM`
6448 
6449   Output Parameter:
6450 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6451 
6452   Level: beginner
6453 
6454 .seealso: `DMSetUseNatural()`, `DMCreate()`
6455 @*/
6456 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
6457 {
6458   PetscFunctionBegin;
6459   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6460   PetscValidBoolPointer(useNatural, 2);
6461   *useNatural = dm->useNatural;
6462   PetscFunctionReturn(PETSC_SUCCESS);
6463 }
6464 
6465 /*@
6466   DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel
6467 
6468   Collective
6469 
6470   Input Parameters:
6471  + dm - The `DM`
6472 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution
6473 
6474   Note:
6475   This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()`
6476 
6477   Level: beginner
6478 
6479 .seealso: `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
6480 @*/
6481 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
6482 {
6483   PetscFunctionBegin;
6484   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6485   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
6486   dm->useNatural = useNatural;
6487   PetscFunctionReturn(PETSC_SUCCESS);
6488 }
6489 
6490 /*@C
6491   DMCreateLabel - Create a label of the given name if it does not already exist in the `DM`
6492 
6493   Not Collective
6494 
6495   Input Parameters:
6496 + dm   - The `DM` object
6497 - name - The label name
6498 
6499   Level: intermediate
6500 
6501 .seealso: `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6502 @*/
6503 PetscErrorCode DMCreateLabel(DM dm, const char name[])
6504 {
6505   PetscBool flg;
6506   DMLabel   label;
6507 
6508   PetscFunctionBegin;
6509   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6510   PetscValidCharPointer(name, 2);
6511   PetscCall(DMHasLabel(dm, name, &flg));
6512   if (!flg) {
6513     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6514     PetscCall(DMAddLabel(dm, label));
6515     PetscCall(DMLabelDestroy(&label));
6516   }
6517   PetscFunctionReturn(PETSC_SUCCESS);
6518 }
6519 
6520 /*@C
6521   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index.
6522 
6523   Not Collective
6524 
6525   Input Parameters:
6526 + dm   - The `DM` object
6527 . l    - The index for the label
6528 - name - The label name
6529 
6530   Level: intermediate
6531 
6532 .seealso: `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6533 @*/
6534 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
6535 {
6536   DMLabelLink orig, prev = NULL;
6537   DMLabel     label;
6538   PetscInt    Nl, m;
6539   PetscBool   flg, match;
6540   const char *lname;
6541 
6542   PetscFunctionBegin;
6543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6544   PetscValidCharPointer(name, 3);
6545   PetscCall(DMHasLabel(dm, name, &flg));
6546   if (!flg) {
6547     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
6548     PetscCall(DMAddLabel(dm, label));
6549     PetscCall(DMLabelDestroy(&label));
6550   }
6551   PetscCall(DMGetNumLabels(dm, &Nl));
6552   PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
6553   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
6554     PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname));
6555     PetscCall(PetscStrcmp(name, lname, &match));
6556     if (match) break;
6557   }
6558   if (m == l) PetscFunctionReturn(PETSC_SUCCESS);
6559   if (!m) dm->labels = orig->next;
6560   else prev->next = orig->next;
6561   if (!l) {
6562     orig->next = dm->labels;
6563     dm->labels = orig;
6564   } else {
6565     for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next)
6566       ;
6567     orig->next = prev->next;
6568     prev->next = orig;
6569   }
6570   PetscFunctionReturn(PETSC_SUCCESS);
6571 }
6572 
6573 /*@C
6574   DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default
6575 
6576   Not Collective
6577 
6578   Input Parameters:
6579 + dm   - The `DM` object
6580 . name - The label name
6581 - point - The mesh point
6582 
6583   Output Parameter:
6584 . value - The label value for this point, or -1 if the point is not in the label
6585 
6586   Level: beginner
6587 
6588 .seealso: `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6589 @*/
6590 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
6591 {
6592   DMLabel label;
6593 
6594   PetscFunctionBegin;
6595   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6596   PetscValidCharPointer(name, 2);
6597   PetscCall(DMGetLabel(dm, name, &label));
6598   PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
6599   PetscCall(DMLabelGetValue(label, point, value));
6600   PetscFunctionReturn(PETSC_SUCCESS);
6601 }
6602 
6603 /*@C
6604   DMSetLabelValue - Add a point to a `DMLabel` with given value
6605 
6606   Not Collective
6607 
6608   Input Parameters:
6609 + dm   - The `DM` object
6610 . name - The label name
6611 . point - The mesh point
6612 - value - The label value for this point
6613 
6614   Output Parameter:
6615 
6616   Level: beginner
6617 
6618 .seealso: `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6619 @*/
6620 PetscErrorCode DMSetLabelValue(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) {
6629     PetscCall(DMCreateLabel(dm, name));
6630     PetscCall(DMGetLabel(dm, name, &label));
6631   }
6632   PetscCall(DMLabelSetValue(label, point, value));
6633   PetscFunctionReturn(PETSC_SUCCESS);
6634 }
6635 
6636 /*@C
6637   DMClearLabelValue - Remove a point from a `DMLabel` with given value
6638 
6639   Not Collective
6640 
6641   Input Parameters:
6642 + dm   - The `DM` object
6643 . name - The label name
6644 . point - The mesh point
6645 - value - The label value for this point
6646 
6647   Level: beginner
6648 
6649 .seealso: `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6650 @*/
6651 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
6652 {
6653   DMLabel label;
6654 
6655   PetscFunctionBegin;
6656   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6657   PetscValidCharPointer(name, 2);
6658   PetscCall(DMGetLabel(dm, name, &label));
6659   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6660   PetscCall(DMLabelClearValue(label, point, value));
6661   PetscFunctionReturn(PETSC_SUCCESS);
6662 }
6663 
6664 /*@C
6665   DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM`
6666 
6667   Not Collective
6668 
6669   Input Parameters:
6670 + dm   - The `DM` object
6671 - name - The label name
6672 
6673   Output Parameter:
6674 . size - The number of different integer ids, or 0 if the label does not exist
6675 
6676   Level: beginner
6677 
6678   Developer Note:
6679   This should be renamed to something like `DMGetLabelNumValues()` or removed.
6680 
6681 .seealso: `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()`
6682 @*/
6683 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
6684 {
6685   DMLabel label;
6686 
6687   PetscFunctionBegin;
6688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6689   PetscValidCharPointer(name, 2);
6690   PetscValidIntPointer(size, 3);
6691   PetscCall(DMGetLabel(dm, name, &label));
6692   *size = 0;
6693   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6694   PetscCall(DMLabelGetNumValues(label, size));
6695   PetscFunctionReturn(PETSC_SUCCESS);
6696 }
6697 
6698 /*@C
6699   DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM`
6700 
6701   Not Collective
6702 
6703   Input Parameters:
6704 + mesh - The `DM` object
6705 - name - The label name
6706 
6707   Output Parameter:
6708 . ids - The integer ids, or `NULL` if the label does not exist
6709 
6710   Level: beginner
6711 
6712 .seealso: `DMLabelGetValueIS()`, `DMGetLabelSize()`
6713 @*/
6714 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
6715 {
6716   DMLabel label;
6717 
6718   PetscFunctionBegin;
6719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6720   PetscValidCharPointer(name, 2);
6721   PetscValidPointer(ids, 3);
6722   PetscCall(DMGetLabel(dm, name, &label));
6723   *ids = NULL;
6724   if (label) {
6725     PetscCall(DMLabelGetValueIS(label, ids));
6726   } else {
6727     /* returning an empty IS */
6728     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids));
6729   }
6730   PetscFunctionReturn(PETSC_SUCCESS);
6731 }
6732 
6733 /*@C
6734   DMGetStratumSize - Get the number of points in a label stratum
6735 
6736   Not Collective
6737 
6738   Input Parameters:
6739 + dm - The `DM` object
6740 . name - The label name
6741 - value - The stratum value
6742 
6743   Output Parameter:
6744 . size - The number of points, also called the stratum size
6745 
6746   Level: beginner
6747 
6748 .seealso: `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
6749 @*/
6750 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
6751 {
6752   DMLabel label;
6753 
6754   PetscFunctionBegin;
6755   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6756   PetscValidCharPointer(name, 2);
6757   PetscValidIntPointer(size, 4);
6758   PetscCall(DMGetLabel(dm, name, &label));
6759   *size = 0;
6760   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6761   PetscCall(DMLabelGetStratumSize(label, value, size));
6762   PetscFunctionReturn(PETSC_SUCCESS);
6763 }
6764 
6765 /*@C
6766   DMGetStratumIS - Get the points in a label stratum
6767 
6768   Not Collective
6769 
6770   Input Parameters:
6771 + dm - The `DM` object
6772 . name - The label name
6773 - value - The stratum value
6774 
6775   Output Parameter:
6776 . points - The stratum points, or `NULL` if the label does not exist or does not have that value
6777 
6778   Level: beginner
6779 
6780 .seealso: `DMLabelGetStratumIS()`, `DMGetStratumSize()`
6781 @*/
6782 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
6783 {
6784   DMLabel label;
6785 
6786   PetscFunctionBegin;
6787   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6788   PetscValidCharPointer(name, 2);
6789   PetscValidPointer(points, 4);
6790   PetscCall(DMGetLabel(dm, name, &label));
6791   *points = NULL;
6792   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6793   PetscCall(DMLabelGetStratumIS(label, value, points));
6794   PetscFunctionReturn(PETSC_SUCCESS);
6795 }
6796 
6797 /*@C
6798   DMSetStratumIS - Set the points in a label stratum
6799 
6800   Not Collective
6801 
6802   Input Parameters:
6803 + dm - The `DM` object
6804 . name - The label name
6805 . value - The stratum value
6806 - points - The stratum points
6807 
6808   Level: beginner
6809 
6810 .seealso: `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()`
6811 @*/
6812 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
6813 {
6814   DMLabel label;
6815 
6816   PetscFunctionBegin;
6817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6818   PetscValidCharPointer(name, 2);
6819   PetscValidPointer(points, 4);
6820   PetscCall(DMGetLabel(dm, name, &label));
6821   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6822   PetscCall(DMLabelSetStratumIS(label, value, points));
6823   PetscFunctionReturn(PETSC_SUCCESS);
6824 }
6825 
6826 /*@C
6827   DMClearLabelStratum - Remove all points from a stratum from a `DMLabel`
6828 
6829   Not Collective
6830 
6831   Input Parameters:
6832 + dm   - The `DM` object
6833 . name - The label name
6834 - value - The label value for this point
6835 
6836   Output Parameter:
6837 
6838   Level: beginner
6839 
6840 .seealso: `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
6841 @*/
6842 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
6843 {
6844   DMLabel label;
6845 
6846   PetscFunctionBegin;
6847   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6848   PetscValidCharPointer(name, 2);
6849   PetscCall(DMGetLabel(dm, name, &label));
6850   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
6851   PetscCall(DMLabelClearStratum(label, value));
6852   PetscFunctionReturn(PETSC_SUCCESS);
6853 }
6854 
6855 /*@
6856   DMGetNumLabels - Return the number of labels defined by on the `DM`
6857 
6858   Not Collective
6859 
6860   Input Parameter:
6861 . dm   - The `DM` object
6862 
6863   Output Parameter:
6864 . numLabels - the number of Labels
6865 
6866   Level: intermediate
6867 
6868 .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6869 @*/
6870 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
6871 {
6872   DMLabelLink next = dm->labels;
6873   PetscInt    n    = 0;
6874 
6875   PetscFunctionBegin;
6876   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6877   PetscValidIntPointer(numLabels, 2);
6878   while (next) {
6879     ++n;
6880     next = next->next;
6881   }
6882   *numLabels = n;
6883   PetscFunctionReturn(PETSC_SUCCESS);
6884 }
6885 
6886 /*@C
6887   DMGetLabelName - Return the name of nth label
6888 
6889   Not Collective
6890 
6891   Input Parameters:
6892 + dm - The `DM` object
6893 - n  - the label number
6894 
6895   Output Parameter:
6896 . name - the label name
6897 
6898   Level: intermediate
6899 
6900   Developer Note:
6901   Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not.
6902 
6903 .seealso: `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6904 @*/
6905 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
6906 {
6907   DMLabelLink next = dm->labels;
6908   PetscInt    l    = 0;
6909 
6910   PetscFunctionBegin;
6911   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6912   PetscValidPointer(name, 3);
6913   while (next) {
6914     if (l == n) {
6915       PetscCall(PetscObjectGetName((PetscObject)next->label, name));
6916       PetscFunctionReturn(PETSC_SUCCESS);
6917     }
6918     ++l;
6919     next = next->next;
6920   }
6921   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
6922 }
6923 
6924 /*@C
6925   DMHasLabel - Determine whether the `DM` has a label of a given name
6926 
6927   Not Collective
6928 
6929   Input Parameters:
6930 + dm   - The `DM` object
6931 - name - The label name
6932 
6933   Output Parameter:
6934 . hasLabel - `PETSC_TRUE` if the label is present
6935 
6936   Level: intermediate
6937 
6938 .seealso: `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
6939 @*/
6940 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
6941 {
6942   DMLabelLink next = dm->labels;
6943   const char *lname;
6944 
6945   PetscFunctionBegin;
6946   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6947   PetscValidCharPointer(name, 2);
6948   PetscValidBoolPointer(hasLabel, 3);
6949   *hasLabel = PETSC_FALSE;
6950   while (next) {
6951     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
6952     PetscCall(PetscStrcmp(name, lname, hasLabel));
6953     if (*hasLabel) break;
6954     next = next->next;
6955   }
6956   PetscFunctionReturn(PETSC_SUCCESS);
6957 }
6958 
6959 /*@C
6960   DMGetLabel - Return the label of a given name, or `NULL`, from a `DM`
6961 
6962   Not Collective
6963 
6964   Input Parameters:
6965 + dm   - The `DM` object
6966 - name - The label name
6967 
6968   Output Parameter:
6969 . label - The `DMLabel`, or `NULL` if the label is absent
6970 
6971   Default labels in a `DMPLEX`:
6972 +   "depth"       - Holds the depth (co-dimension) of each mesh point
6973 .   "celltype"    - Holds the topological type of each cell
6974 .   "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
6975 .   "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
6976 .   "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
6977 -  "Vertex Sets" - Mirrors the vertex sets defined by GMsh
6978 
6979   Level: intermediate
6980 
6981 .seealso: `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
6982 @*/
6983 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
6984 {
6985   DMLabelLink next = dm->labels;
6986   PetscBool   hasLabel;
6987   const char *lname;
6988 
6989   PetscFunctionBegin;
6990   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6991   PetscValidCharPointer(name, 2);
6992   PetscValidPointer(label, 3);
6993   *label = NULL;
6994   while (next) {
6995     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
6996     PetscCall(PetscStrcmp(name, lname, &hasLabel));
6997     if (hasLabel) {
6998       *label = next->label;
6999       break;
7000     }
7001     next = next->next;
7002   }
7003   PetscFunctionReturn(PETSC_SUCCESS);
7004 }
7005 
7006 /*@C
7007   DMGetLabelByNum - Return the nth label on a `DM`
7008 
7009   Not Collective
7010 
7011   Input Parameters:
7012 + dm - The `DM` object
7013 - n  - the label number
7014 
7015   Output Parameter:
7016 . label - the label
7017 
7018   Level: intermediate
7019 
7020 .seealso: `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7021 @*/
7022 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7023 {
7024   DMLabelLink next = dm->labels;
7025   PetscInt    l    = 0;
7026 
7027   PetscFunctionBegin;
7028   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7029   PetscValidPointer(label, 3);
7030   while (next) {
7031     if (l == n) {
7032       *label = next->label;
7033       PetscFunctionReturn(PETSC_SUCCESS);
7034     }
7035     ++l;
7036     next = next->next;
7037   }
7038   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7039 }
7040 
7041 /*@C
7042   DMAddLabel - Add the label to this `DM`
7043 
7044   Not Collective
7045 
7046   Input Parameters:
7047 + dm   - The `DM` object
7048 - label - The `DMLabel`
7049 
7050   Level: developer
7051 
7052 .seealso: `DMLabel`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7053 @*/
7054 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7055 {
7056   DMLabelLink l, *p, tmpLabel;
7057   PetscBool   hasLabel;
7058   const char *lname;
7059   PetscBool   flg;
7060 
7061   PetscFunctionBegin;
7062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7063   PetscCall(PetscObjectGetName((PetscObject)label, &lname));
7064   PetscCall(DMHasLabel(dm, lname, &hasLabel));
7065   PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7066   PetscCall(PetscCalloc1(1, &tmpLabel));
7067   tmpLabel->label  = label;
7068   tmpLabel->output = PETSC_TRUE;
7069   for (p = &dm->labels; (l = *p); p = &l->next) { }
7070   *p = tmpLabel;
7071   PetscCall(PetscObjectReference((PetscObject)label));
7072   PetscCall(PetscStrcmp(lname, "depth", &flg));
7073   if (flg) dm->depthLabel = label;
7074   PetscCall(PetscStrcmp(lname, "celltype", &flg));
7075   if (flg) dm->celltypeLabel = label;
7076   PetscFunctionReturn(PETSC_SUCCESS);
7077 }
7078 
7079 /*@C
7080   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
7081 
7082   Not Collective
7083 
7084   Input Parameters:
7085 + dm    - The `DM` object
7086 - label - The `DMLabel`, having the same name, to substitute
7087 
7088   Default labels in a `DMPLEX`:
7089 +  "depth"       - Holds the depth (co-dimension) of each mesh point
7090 .  "celltype"    - Holds the topological type of each cell
7091 .  "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7092 .  "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7093 .  "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7094 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7095 
7096   Level: intermediate
7097 
7098 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7099 @*/
7100 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
7101 {
7102   DMLabelLink next = dm->labels;
7103   PetscBool   hasLabel, flg;
7104   const char *name, *lname;
7105 
7106   PetscFunctionBegin;
7107   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7108   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
7109   PetscCall(PetscObjectGetName((PetscObject)label, &name));
7110   while (next) {
7111     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7112     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7113     if (hasLabel) {
7114       PetscCall(PetscObjectReference((PetscObject)label));
7115       PetscCall(PetscStrcmp(lname, "depth", &flg));
7116       if (flg) dm->depthLabel = label;
7117       PetscCall(PetscStrcmp(lname, "celltype", &flg));
7118       if (flg) dm->celltypeLabel = label;
7119       PetscCall(DMLabelDestroy(&next->label));
7120       next->label = label;
7121       break;
7122     }
7123     next = next->next;
7124   }
7125   PetscFunctionReturn(PETSC_SUCCESS);
7126 }
7127 
7128 /*@C
7129   DMRemoveLabel - Remove the label given by name from this `DM`
7130 
7131   Not Collective
7132 
7133   Input Parameters:
7134 + dm   - The `DM` object
7135 - name - The label name
7136 
7137   Output Parameter:
7138 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the
7139           caller is responsible for calling `DMLabelDestroy()`.
7140 
7141   Level: developer
7142 
7143 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
7144 @*/
7145 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7146 {
7147   DMLabelLink link, *pnext;
7148   PetscBool   hasLabel;
7149   const char *lname;
7150 
7151   PetscFunctionBegin;
7152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7153   PetscValidCharPointer(name, 2);
7154   if (label) {
7155     PetscValidPointer(label, 3);
7156     *label = NULL;
7157   }
7158   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7159     PetscCall(PetscObjectGetName((PetscObject)link->label, &lname));
7160     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7161     if (hasLabel) {
7162       *pnext = link->next; /* Remove from list */
7163       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
7164       if (hasLabel) dm->depthLabel = NULL;
7165       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
7166       if (hasLabel) dm->celltypeLabel = NULL;
7167       if (label) *label = link->label;
7168       else PetscCall(DMLabelDestroy(&link->label));
7169       PetscCall(PetscFree(link));
7170       break;
7171     }
7172   }
7173   PetscFunctionReturn(PETSC_SUCCESS);
7174 }
7175 
7176 /*@
7177   DMRemoveLabelBySelf - Remove the label from this `DM`
7178 
7179   Not Collective
7180 
7181   Input Parameters:
7182 + dm   - The `DM` object
7183 . label - The `DMLabel` to be removed from the `DM`
7184 - failNotFound - Should it fail if the label is not found in the `DM`?
7185 
7186   Level: developer
7187 
7188   Note:
7189   Only exactly the same instance is removed if found, name match is ignored.
7190   If the `DM` has an exclusive reference to the label, the label gets destroyed and
7191   *label nullified.
7192 
7193 .seealso: `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
7194 @*/
7195 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7196 {
7197   DMLabelLink link, *pnext;
7198   PetscBool   hasLabel = PETSC_FALSE;
7199 
7200   PetscFunctionBegin;
7201   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7202   PetscValidPointer(label, 2);
7203   if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS);
7204   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7205   PetscValidLogicalCollectiveBool(dm, failNotFound, 3);
7206   for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) {
7207     if (*label == link->label) {
7208       hasLabel = PETSC_TRUE;
7209       *pnext   = link->next; /* Remove from list */
7210       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7211       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7212       if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7213       PetscCall(DMLabelDestroy(&link->label));
7214       PetscCall(PetscFree(link));
7215       break;
7216     }
7217   }
7218   PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7219   PetscFunctionReturn(PETSC_SUCCESS);
7220 }
7221 
7222 /*@C
7223   DMGetLabelOutput - Get the output flag for a given label
7224 
7225   Not Collective
7226 
7227   Input Parameters:
7228 + dm   - The `DM` object
7229 - name - The label name
7230 
7231   Output Parameter:
7232 . output - The flag for output
7233 
7234   Level: developer
7235 
7236 .seealso: `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7237 @*/
7238 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7239 {
7240   DMLabelLink next = dm->labels;
7241   const char *lname;
7242 
7243   PetscFunctionBegin;
7244   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7245   PetscValidCharPointer(name, 2);
7246   PetscValidBoolPointer(output, 3);
7247   while (next) {
7248     PetscBool flg;
7249 
7250     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7251     PetscCall(PetscStrcmp(name, lname, &flg));
7252     if (flg) {
7253       *output = next->output;
7254       PetscFunctionReturn(PETSC_SUCCESS);
7255     }
7256     next = next->next;
7257   }
7258   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7259 }
7260 
7261 /*@C
7262   DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()`
7263 
7264   Not Collective
7265 
7266   Input Parameters:
7267 + dm     - The `DM` object
7268 . name   - The label name
7269 - output - `PETSC_TRUE` to save the label to the viewer
7270 
7271   Level: developer
7272 
7273 .seealso: `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7274 @*/
7275 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7276 {
7277   DMLabelLink next = dm->labels;
7278   const char *lname;
7279 
7280   PetscFunctionBegin;
7281   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7282   PetscValidCharPointer(name, 2);
7283   while (next) {
7284     PetscBool flg;
7285 
7286     PetscCall(PetscObjectGetName((PetscObject)next->label, &lname));
7287     PetscCall(PetscStrcmp(name, lname, &flg));
7288     if (flg) {
7289       next->output = output;
7290       PetscFunctionReturn(PETSC_SUCCESS);
7291     }
7292     next = next->next;
7293   }
7294   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7295 }
7296 
7297 /*@
7298   DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points
7299 
7300   Collective
7301 
7302   Input Parameters:
7303 + dmA - The `DM` object with initial labels
7304 . dmB - The `DM` object to which labels are copied
7305 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`)
7306 . all  - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`)
7307 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`)
7308 
7309   Level: intermediate
7310 
7311   Note:
7312   This is typically used when interpolating or otherwise adding to a mesh, or testing.
7313 
7314 .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`
7315 @*/
7316 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
7317 {
7318   DMLabel     label, labelNew, labelOld;
7319   const char *name;
7320   PetscBool   flg;
7321   DMLabelLink link;
7322 
7323   PetscFunctionBegin;
7324   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7325   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7326   PetscValidLogicalCollectiveEnum(dmA, mode, 3);
7327   PetscValidLogicalCollectiveBool(dmA, all, 4);
7328   PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7329   if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS);
7330   for (link = dmA->labels; link; link = link->next) {
7331     label = link->label;
7332     PetscCall(PetscObjectGetName((PetscObject)label, &name));
7333     if (!all) {
7334       PetscCall(PetscStrcmp(name, "depth", &flg));
7335       if (flg) continue;
7336       PetscCall(PetscStrcmp(name, "dim", &flg));
7337       if (flg) continue;
7338       PetscCall(PetscStrcmp(name, "celltype", &flg));
7339       if (flg) continue;
7340     }
7341     PetscCall(DMGetLabel(dmB, name, &labelOld));
7342     if (labelOld) {
7343       switch (emode) {
7344       case DM_COPY_LABELS_KEEP:
7345         continue;
7346       case DM_COPY_LABELS_REPLACE:
7347         PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
7348         break;
7349       case DM_COPY_LABELS_FAIL:
7350         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
7351       default:
7352         SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
7353       }
7354     }
7355     if (mode == PETSC_COPY_VALUES) {
7356       PetscCall(DMLabelDuplicate(label, &labelNew));
7357     } else {
7358       labelNew = label;
7359     }
7360     PetscCall(DMAddLabel(dmB, labelNew));
7361     if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
7362   }
7363   PetscFunctionReturn(PETSC_SUCCESS);
7364 }
7365 
7366 /*@C
7367   DMCompareLabels - Compare labels of two `DMPLEX` meshes
7368 
7369   Collective; No Fortran Support
7370 
7371   Input Parameters:
7372 + dm0 - First `DM` object
7373 - dm1 - Second `DM` object
7374 
7375   Output Parameters
7376 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
7377 - message - (Optional) Message describing the difference, or `NULL` if there is no difference
7378 
7379   Level: intermediate
7380 
7381   Notes:
7382   The output flag equal will be the same on all processes.
7383 
7384   If equal is passed as `NULL` and difference is found, an error is thrown on all processes.
7385 
7386   Make sure to pass equal is `NULL` on all processes or none of them.
7387 
7388   The output message is set independently on each rank.
7389 
7390   message must be freed with `PetscFree()`
7391 
7392   If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner.
7393 
7394   Make sure to pass message as `NULL` on all processes or no processes.
7395 
7396   Labels are matched by name. If the number of labels and their names are equal,
7397   `DMLabelCompare()` is used to compare each pair of labels with the same name.
7398 
7399 .seealso: `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
7400 @*/
7401 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
7402 {
7403   PetscInt    n, i;
7404   char        msg[PETSC_MAX_PATH_LEN] = "";
7405   PetscBool   eq;
7406   MPI_Comm    comm;
7407   PetscMPIInt rank;
7408 
7409   PetscFunctionBegin;
7410   PetscValidHeaderSpecific(dm0, DM_CLASSID, 1);
7411   PetscValidHeaderSpecific(dm1, DM_CLASSID, 2);
7412   PetscCheckSameComm(dm0, 1, dm1, 2);
7413   if (equal) PetscValidBoolPointer(equal, 3);
7414   if (message) PetscValidPointer(message, 4);
7415   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
7416   PetscCallMPI(MPI_Comm_rank(comm, &rank));
7417   {
7418     PetscInt n1;
7419 
7420     PetscCall(DMGetNumLabels(dm0, &n));
7421     PetscCall(DMGetNumLabels(dm1, &n1));
7422     eq = (PetscBool)(n == n1);
7423     if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
7424     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7425     if (!eq) goto finish;
7426   }
7427   for (i = 0; i < n; i++) {
7428     DMLabel     l0, l1;
7429     const char *name;
7430     char       *msgInner;
7431 
7432     /* Ignore label order */
7433     PetscCall(DMGetLabelByNum(dm0, i, &l0));
7434     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
7435     PetscCall(DMGetLabel(dm1, name, &l1));
7436     if (!l1) {
7437       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
7438       eq = PETSC_FALSE;
7439       break;
7440     }
7441     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
7442     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
7443     PetscCall(PetscFree(msgInner));
7444     if (!eq) break;
7445   }
7446   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
7447 finish:
7448   /* If message output arg not set, print to stderr */
7449   if (message) {
7450     *message = NULL;
7451     if (msg[0]) PetscCall(PetscStrallocpy(msg, message));
7452   } else {
7453     if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
7454     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
7455   }
7456   /* If same output arg not ser and labels are not equal, throw error */
7457   if (equal) *equal = eq;
7458   else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
7459   PetscFunctionReturn(PETSC_SUCCESS);
7460 }
7461 
7462 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
7463 {
7464   PetscFunctionBegin;
7465   PetscValidPointer(label, 2);
7466   if (!*label) {
7467     PetscCall(DMCreateLabel(dm, name));
7468     PetscCall(DMGetLabel(dm, name, label));
7469   }
7470   PetscCall(DMLabelSetValue(*label, point, value));
7471   PetscFunctionReturn(PETSC_SUCCESS);
7472 }
7473 
7474 /*
7475   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7476   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7477   (label, id) pair in the DM.
7478 
7479   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7480   each label.
7481 */
7482 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7483 {
7484   DMUniversalLabel ul;
7485   PetscBool       *active;
7486   PetscInt         pStart, pEnd, p, Nl, l, m;
7487 
7488   PetscFunctionBegin;
7489   PetscCall(PetscMalloc1(1, &ul));
7490   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
7491   PetscCall(DMGetNumLabels(dm, &Nl));
7492   PetscCall(PetscCalloc1(Nl, &active));
7493   ul->Nl = 0;
7494   for (l = 0; l < Nl; ++l) {
7495     PetscBool   isdepth, iscelltype;
7496     const char *name;
7497 
7498     PetscCall(DMGetLabelName(dm, l, &name));
7499     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
7500     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
7501     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7502     if (active[l]) ++ul->Nl;
7503   }
7504   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks));
7505   ul->Nv = 0;
7506   for (l = 0, m = 0; l < Nl; ++l) {
7507     DMLabel     label;
7508     PetscInt    nv;
7509     const char *name;
7510 
7511     if (!active[l]) continue;
7512     PetscCall(DMGetLabelName(dm, l, &name));
7513     PetscCall(DMGetLabelByNum(dm, l, &label));
7514     PetscCall(DMLabelGetNumValues(label, &nv));
7515     PetscCall(PetscStrallocpy(name, &ul->names[m]));
7516     ul->indices[m] = l;
7517     ul->Nv += nv;
7518     ul->offsets[m + 1] = nv;
7519     ul->bits[m + 1]    = PetscCeilReal(PetscLog2Real(nv + 1));
7520     ++m;
7521   }
7522   for (l = 1; l <= ul->Nl; ++l) {
7523     ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l];
7524     ul->bits[l]    = ul->bits[l - 1] + ul->bits[l];
7525   }
7526   for (l = 0; l < ul->Nl; ++l) {
7527     PetscInt b;
7528 
7529     ul->masks[l] = 0;
7530     for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b;
7531   }
7532   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
7533   for (l = 0, m = 0; l < Nl; ++l) {
7534     DMLabel         label;
7535     IS              valueIS;
7536     const PetscInt *varr;
7537     PetscInt        nv, v;
7538 
7539     if (!active[l]) continue;
7540     PetscCall(DMGetLabelByNum(dm, l, &label));
7541     PetscCall(DMLabelGetNumValues(label, &nv));
7542     PetscCall(DMLabelGetValueIS(label, &valueIS));
7543     PetscCall(ISGetIndices(valueIS, &varr));
7544     for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v];
7545     PetscCall(ISRestoreIndices(valueIS, &varr));
7546     PetscCall(ISDestroy(&valueIS));
7547     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
7548     ++m;
7549   }
7550   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
7551   for (p = pStart; p < pEnd; ++p) {
7552     PetscInt  uval   = 0;
7553     PetscBool marked = PETSC_FALSE;
7554 
7555     for (l = 0, m = 0; l < Nl; ++l) {
7556       DMLabel  label;
7557       PetscInt val, defval, loc, nv;
7558 
7559       if (!active[l]) continue;
7560       PetscCall(DMGetLabelByNum(dm, l, &label));
7561       PetscCall(DMLabelGetValue(label, p, &val));
7562       PetscCall(DMLabelGetDefaultValue(label, &defval));
7563       if (val == defval) {
7564         ++m;
7565         continue;
7566       }
7567       nv     = ul->offsets[m + 1] - ul->offsets[m];
7568       marked = PETSC_TRUE;
7569       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
7570       PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
7571       uval += (loc + 1) << ul->bits[m];
7572       ++m;
7573     }
7574     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
7575   }
7576   PetscCall(PetscFree(active));
7577   *universal = ul;
7578   PetscFunctionReturn(PETSC_SUCCESS);
7579 }
7580 
7581 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
7582 {
7583   PetscInt l;
7584 
7585   PetscFunctionBegin;
7586   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
7587   PetscCall(DMLabelDestroy(&(*universal)->label));
7588   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
7589   PetscCall(PetscFree((*universal)->values));
7590   PetscCall(PetscFree(*universal));
7591   *universal = NULL;
7592   PetscFunctionReturn(PETSC_SUCCESS);
7593 }
7594 
7595 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
7596 {
7597   PetscFunctionBegin;
7598   PetscValidPointer(ulabel, 2);
7599   *ulabel = ul->label;
7600   PetscFunctionReturn(PETSC_SUCCESS);
7601 }
7602 
7603 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
7604 {
7605   PetscInt Nl = ul->Nl, l;
7606 
7607   PetscFunctionBegin;
7608   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
7609   for (l = 0; l < Nl; ++l) {
7610     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
7611     else PetscCall(DMCreateLabel(dm, ul->names[l]));
7612   }
7613   if (preserveOrder) {
7614     for (l = 0; l < ul->Nl; ++l) {
7615       const char *name;
7616       PetscBool   match;
7617 
7618       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
7619       PetscCall(PetscStrcmp(name, ul->names[l], &match));
7620       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]);
7621     }
7622   }
7623   PetscFunctionReturn(PETSC_SUCCESS);
7624 }
7625 
7626 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
7627 {
7628   PetscInt l;
7629 
7630   PetscFunctionBegin;
7631   for (l = 0; l < ul->Nl; ++l) {
7632     DMLabel  label;
7633     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
7634 
7635     if (lval) {
7636       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
7637       else PetscCall(DMGetLabel(dm, ul->names[l], &label));
7638       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1]));
7639     }
7640   }
7641   PetscFunctionReturn(PETSC_SUCCESS);
7642 }
7643 
7644 /*@
7645   DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement
7646 
7647   Not Collective
7648 
7649   Input Parameter:
7650 . dm - The `DM` object
7651 
7652   Output Parameter:
7653 . cdm - The coarse `DM`
7654 
7655   Level: intermediate
7656 
7657 .seealso: `DMSetCoarseDM()`, `DMCoarsen()`
7658 @*/
7659 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
7660 {
7661   PetscFunctionBegin;
7662   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7663   PetscValidPointer(cdm, 2);
7664   *cdm = dm->coarseMesh;
7665   PetscFunctionReturn(PETSC_SUCCESS);
7666 }
7667 
7668 /*@
7669   DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement
7670 
7671   Input Parameters:
7672 + dm - The `DM` object
7673 - cdm - The coarse `DM`
7674 
7675   Level: intermediate
7676 
7677   Note:
7678   Normally this is set automatically by `DMRefine()`
7679 
7680 .seealso: `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()`
7681 @*/
7682 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
7683 {
7684   PetscFunctionBegin;
7685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7686   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
7687   if (dm == cdm) cdm = NULL;
7688   PetscCall(PetscObjectReference((PetscObject)cdm));
7689   PetscCall(DMDestroy(&dm->coarseMesh));
7690   dm->coarseMesh = cdm;
7691   PetscFunctionReturn(PETSC_SUCCESS);
7692 }
7693 
7694 /*@
7695   DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening
7696 
7697   Input Parameter:
7698 . dm - The `DM` object
7699 
7700   Output Parameter:
7701 . fdm - The fine `DM`
7702 
7703   Level: intermediate
7704 
7705 .seealso: `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()`
7706 @*/
7707 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
7708 {
7709   PetscFunctionBegin;
7710   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7711   PetscValidPointer(fdm, 2);
7712   *fdm = dm->fineMesh;
7713   PetscFunctionReturn(PETSC_SUCCESS);
7714 }
7715 
7716 /*@
7717   DMSetFineDM - Set the fine mesh from which this was obtained by coarsening
7718 
7719   Input Parameters:
7720 + dm - The `DM` object
7721 - fdm - The fine `DM`
7722 
7723   Level: developer
7724 
7725   Note:
7726   Normally this is set automatically by `DMCoarsen()`
7727 
7728 .seealso: `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()`
7729 @*/
7730 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
7731 {
7732   PetscFunctionBegin;
7733   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7734   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
7735   if (dm == fdm) fdm = NULL;
7736   PetscCall(PetscObjectReference((PetscObject)fdm));
7737   PetscCall(DMDestroy(&dm->fineMesh));
7738   dm->fineMesh = fdm;
7739   PetscFunctionReturn(PETSC_SUCCESS);
7740 }
7741 
7742 /*@C
7743   DMAddBoundary - Add a boundary condition to a model represented by a `DM`
7744 
7745   Collective
7746 
7747   Input Parameters:
7748 + dm       - The `DM`, with a `PetscDS` that matches the problem being constrained
7749 . type     - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann)
7750 . name     - The BC name
7751 . label    - The label defining constrained points
7752 . Nv       - The number of `DMLabel` values for constrained points
7753 . values   - An array of values for constrained points
7754 . field    - The field to constrain
7755 . Nc       - The number of constrained field components (0 will constrain all fields)
7756 . comps    - An array of constrained component numbers
7757 . bcFunc   - A pointwise function giving boundary values
7758 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
7759 - ctx      - An optional user context for bcFunc
7760 
7761   Output Parameter:
7762 . bd          - (Optional) Boundary number
7763 
7764   Options Database Keys:
7765 + -bc_<boundary name> <num> - Overrides the boundary ids
7766 - -bc_<boundary name>_comp <num> - Overrides the boundary components
7767 
7768   Level: intermediate
7769 
7770   Notes:
7771   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is:
7772 
7773 $ void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
7774 
7775   If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is:
7776 
7777 .vb
7778   void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
7779               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
7780               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
7781               PetscReal time, const PetscReal x[], PetscScalar bcval[])
7782 .ve
7783 + dim - the spatial dimension
7784 . Nf - the number of fields
7785 . uOff - the offset into u[] and u_t[] for each field
7786 . uOff_x - the offset into u_x[] for each field
7787 . u - each field evaluated at the current point
7788 . u_t - the time derivative of each field evaluated at the current point
7789 . u_x - the gradient of each field evaluated at the current point
7790 . aOff - the offset into a[] and a_t[] for each auxiliary field
7791 . aOff_x - the offset into a_x[] for each auxiliary field
7792 . a - each auxiliary field evaluated at the current point
7793 . a_t - the time derivative of each auxiliary field evaluated at the current point
7794 . a_x - the gradient of auxiliary each field evaluated at the current point
7795 . t - current time
7796 . x - coordinates of the current point
7797 . numConstants - number of constant parameters
7798 . constants - constant parameters
7799 - bcval - output values at the current point
7800 
7801 .seealso: `DSGetBoundary()`, `PetscDSAddBoundary()`
7802 @*/
7803 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)
7804 {
7805   PetscDS ds;
7806 
7807   PetscFunctionBegin;
7808   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7809   PetscValidLogicalCollectiveEnum(dm, type, 2);
7810   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
7811   PetscValidLogicalCollectiveInt(dm, Nv, 5);
7812   PetscValidLogicalCollectiveInt(dm, field, 7);
7813   PetscValidLogicalCollectiveInt(dm, Nc, 8);
7814   PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section");
7815   PetscCall(DMGetDS(dm, &ds));
7816   /* Complete label */
7817   if (label) {
7818     PetscObject  obj;
7819     PetscClassId id;
7820 
7821     PetscCall(DMGetField(dm, field, NULL, &obj));
7822     PetscCall(PetscObjectGetClassId(obj, &id));
7823     if (id == PETSCFE_CLASSID) {
7824       DM plex;
7825 
7826       PetscCall(DMConvert(dm, DMPLEX, &plex));
7827       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
7828       PetscCall(DMDestroy(&plex));
7829     }
7830   }
7831   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
7832   PetscFunctionReturn(PETSC_SUCCESS);
7833 }
7834 
7835 /* TODO Remove this since now the structures are the same */
7836 static PetscErrorCode DMPopulateBoundary(DM dm)
7837 {
7838   PetscDS     ds;
7839   DMBoundary *lastnext;
7840   DSBoundary  dsbound;
7841 
7842   PetscFunctionBegin;
7843   PetscCall(DMGetDS(dm, &ds));
7844   dsbound = ds->boundary;
7845   if (dm->boundary) {
7846     DMBoundary next = dm->boundary;
7847 
7848     /* quick check to see if the PetscDS has changed */
7849     if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS);
7850     /* the PetscDS has changed: tear down and rebuild */
7851     while (next) {
7852       DMBoundary b = next;
7853 
7854       next = b->next;
7855       PetscCall(PetscFree(b));
7856     }
7857     dm->boundary = NULL;
7858   }
7859 
7860   lastnext = &(dm->boundary);
7861   while (dsbound) {
7862     DMBoundary dmbound;
7863 
7864     PetscCall(PetscNew(&dmbound));
7865     dmbound->dsboundary = dsbound;
7866     dmbound->label      = dsbound->label;
7867     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
7868     *lastnext = dmbound;
7869     lastnext  = &(dmbound->next);
7870     dsbound   = dsbound->next;
7871   }
7872   PetscFunctionReturn(PETSC_SUCCESS);
7873 }
7874 
7875 /* TODO: missing manual page */
7876 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
7877 {
7878   DMBoundary b;
7879 
7880   PetscFunctionBegin;
7881   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7882   PetscValidBoolPointer(isBd, 3);
7883   *isBd = PETSC_FALSE;
7884   PetscCall(DMPopulateBoundary(dm));
7885   b = dm->boundary;
7886   while (b && !(*isBd)) {
7887     DMLabel    label = b->label;
7888     DSBoundary dsb   = b->dsboundary;
7889     PetscInt   i;
7890 
7891     if (label) {
7892       for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
7893     }
7894     b = b->next;
7895   }
7896   PetscFunctionReturn(PETSC_SUCCESS);
7897 }
7898 
7899 /*@C
7900   DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector.
7901 
7902   Collective
7903 
7904   Input Parameters:
7905 + dm      - The `DM`
7906 . time    - The time
7907 . funcs   - The coordinate functions to evaluate, one per field
7908 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7909 - mode    - The insertion mode for values
7910 
7911   Output Parameter:
7912 . X - vector
7913 
7914    Calling sequence of `funcs`:
7915 $  PetscErrorCode funcs(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7916 +  dim - The spatial dimension
7917 .  time - The time at which to sample
7918 .  x   - The coordinates
7919 .  Nc  - The number of components
7920 .  u   - The output field values
7921 -  ctx - optional user-defined function context
7922 
7923   Level: developer
7924 
7925   Developer Notes:
7926   This API is specific to only particular usage of `DM`
7927 
7928   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7929 
7930 .seealso: `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7931 @*/
7932 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
7933 {
7934   Vec localX;
7935 
7936   PetscFunctionBegin;
7937   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7938   PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0));
7939   PetscCall(DMGetLocalVector(dm, &localX));
7940   PetscCall(VecSet(localX, 0.));
7941   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
7942   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
7943   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
7944   PetscCall(DMRestoreLocalVector(dm, &localX));
7945   PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0));
7946   PetscFunctionReturn(PETSC_SUCCESS);
7947 }
7948 
7949 /*@C
7950   DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector.
7951 
7952   Not Collective
7953 
7954   Input Parameters:
7955 + dm      - The `DM`
7956 . time    - The time
7957 . funcs   - The coordinate functions to evaluate, one per field
7958 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
7959 - mode    - The insertion mode for values
7960 
7961   Output Parameter:
7962 . localX - vector
7963 
7964    Calling sequence of `funcs`:
7965 $  PetscErrorCode funcs(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
7966 +  dim - The spatial dimension
7967 .  x   - The coordinates
7968 .  Nc  - The number of components
7969 .  u   - The output field values
7970 -  ctx - optional user-defined function context
7971 
7972   Level: developer
7973 
7974   Developer Notes:
7975   This API is specific to only particular usage of `DM`
7976 
7977   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
7978 
7979 .seealso: `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
7980 @*/
7981 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
7982 {
7983   PetscFunctionBegin;
7984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7985   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
7986   PetscCall((dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX));
7987   PetscFunctionReturn(PETSC_SUCCESS);
7988 }
7989 
7990 /*@C
7991   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.
7992 
7993   Collective
7994 
7995   Input Parameters:
7996 + dm      - The `DM`
7997 . time    - The time
7998 . label   - The `DMLabel` selecting the portion of the mesh for projection
7999 . funcs   - The coordinate functions to evaluate, one per field
8000 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs may be null.
8001 - mode    - The insertion mode for values
8002 
8003   Output Parameter:
8004 . X - vector
8005 
8006    Calling sequence of `funcs`:
8007 $  PetscErrorCode funcs(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8008 +  dim - The spatial dimension
8009 .  x   - The coordinates
8010 .  Nc  - The number of components
8011 .  u   - The output field values
8012 -  ctx - optional user-defined function context
8013 
8014   Level: developer
8015 
8016   Developer Notes:
8017   This API is specific to only particular usage of `DM`
8018 
8019   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8020 
8021 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8022 @*/
8023 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)
8024 {
8025   Vec localX;
8026 
8027   PetscFunctionBegin;
8028   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8029   PetscCall(DMGetLocalVector(dm, &localX));
8030   PetscCall(VecSet(localX, 0.));
8031   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8032   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8033   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8034   PetscCall(DMRestoreLocalVector(dm, &localX));
8035   PetscFunctionReturn(PETSC_SUCCESS);
8036 }
8037 
8038 /*@C
8039   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.
8040 
8041   Not Collective
8042 
8043   Input Parameters:
8044 + dm      - The `DM`
8045 . time    - The time
8046 . label   - The `DMLabel` selecting the portion of the mesh for projection
8047 . funcs   - The coordinate functions to evaluate, one per field
8048 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8049 - mode    - The insertion mode for values
8050 
8051   Output Parameter:
8052 . localX - vector
8053 
8054    Calling sequence of `funcs`:
8055 $  PetscErrorCode funcs(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8056 +  dim - The spatial dimension
8057 .  x   - The coordinates
8058 .  Nc  - The number of components
8059 .  u   - The output field values
8060 -  ctx - optional user-defined function context
8061 
8062   Level: developer
8063 
8064   Developer Notes:
8065   This API is specific to only particular usage of `DM`
8066 
8067   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8068 
8069 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8070 @*/
8071 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)
8072 {
8073   PetscFunctionBegin;
8074   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8075   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8076   PetscCall((dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8077   PetscFunctionReturn(PETSC_SUCCESS);
8078 }
8079 
8080 /*@C
8081   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.
8082 
8083   Not Collective
8084 
8085   Input Parameters:
8086 + dm      - The `DM`
8087 . time    - The time
8088 . localU  - The input field vector; may be `NULL` if projection is defined purely by coordinates
8089 . funcs   - The functions to evaluate, one per field
8090 - mode    - The insertion mode for values
8091 
8092   Output Parameter:
8093 . localX  - The output vector
8094 
8095    Calling sequence of `funcs`:
8096 .vb
8097    void funcs(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8098               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8099               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8100               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8101 .ve
8102 +  dim          - The spatial dimension
8103 .  Nf           - The number of input fields
8104 .  NfAux        - The number of input auxiliary fields
8105 .  uOff         - The offset of each field in u[]
8106 .  uOff_x       - The offset of each field in u_x[]
8107 .  u            - The field values at this point in space
8108 .  u_t          - The field time derivative at this point in space (or NULL)
8109 .  u_x          - The field derivatives at this point in space
8110 .  aOff         - The offset of each auxiliary field in u[]
8111 .  aOff_x       - The offset of each auxiliary field in u_x[]
8112 .  a            - The auxiliary field values at this point in space
8113 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8114 .  a_x          - The auxiliary field derivatives at this point in space
8115 .  t            - The current time
8116 .  x            - The coordinates of this point
8117 .  numConstants - The number of constants
8118 .  constants    - The value of each constant
8119 -  f            - The value of the function at this point in space
8120 
8121   Note:
8122   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.
8123   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
8124   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8125   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8126 
8127   Level: intermediate
8128 
8129   Developer Notes:
8130   This API is specific to only particular usage of `DM`
8131 
8132   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8133 
8134 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8135 @*/
8136 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)
8137 {
8138   PetscFunctionBegin;
8139   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8140   if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3);
8141   PetscValidHeaderSpecific(localX, VEC_CLASSID, 6);
8142   PetscCall((dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX));
8143   PetscFunctionReturn(PETSC_SUCCESS);
8144 }
8145 
8146 /*@C
8147   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.
8148 
8149   Not Collective
8150 
8151   Input Parameters:
8152 + dm      - The `DM`
8153 . time    - The time
8154 . label   - The `DMLabel` marking the portion of the domain to output
8155 . numIds  - The number of label ids to use
8156 . ids     - The label ids to use for marking
8157 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8158 . comps   - The components to set in the output, or `NULL` for all components
8159 . localU  - The input field vector
8160 . funcs   - The functions to evaluate, one per field
8161 - mode    - The insertion mode for values
8162 
8163   Output Parameter:
8164 . localX  - The output vector
8165 
8166    Calling sequence of `funcs`:
8167 .vb
8168    void funcs(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8169               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8170               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8171               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8172 .ve
8173 +  dim          - The spatial dimension
8174 .  Nf           - The number of input fields
8175 .  NfAux        - The number of input auxiliary fields
8176 .  uOff         - The offset of each field in u[]
8177 .  uOff_x       - The offset of each field in u_x[]
8178 .  u            - The field values at this point in space
8179 .  u_t          - The field time derivative at this point in space (or NULL)
8180 .  u_x          - The field derivatives at this point in space
8181 .  aOff         - The offset of each auxiliary field in u[]
8182 .  aOff_x       - The offset of each auxiliary field in u_x[]
8183 .  a            - The auxiliary field values at this point in space
8184 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8185 .  a_x          - The auxiliary field derivatives at this point in space
8186 .  t            - The current time
8187 .  x            - The coordinates of this point
8188 .  numConstants - The number of constants
8189 .  constants    - The value of each constant
8190 -  f            - The value of the function at this point in space
8191 
8192   Note:
8193   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.
8194   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
8195   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8196   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8197 
8198   Level: intermediate
8199 
8200   Developer Notes:
8201   This API is specific to only particular usage of `DM`
8202 
8203   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8204 
8205 .seealso: `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8206 @*/
8207 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)
8208 {
8209   PetscFunctionBegin;
8210   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8211   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8212   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8213   PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8214   PetscFunctionReturn(PETSC_SUCCESS);
8215 }
8216 
8217 /*@C
8218   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.
8219 
8220   Not Collective
8221 
8222   Input Parameters:
8223 + dm      - The `DM`
8224 . time    - The time
8225 . label   - The `DMLabel` marking the portion of the domain to output
8226 . numIds  - The number of label ids to use
8227 . ids     - The label ids to use for marking
8228 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8229 . comps   - The components to set in the output, or `NULL` for all components
8230 . U       - The input field vector
8231 . funcs   - The functions to evaluate, one per field
8232 - mode    - The insertion mode for values
8233 
8234   Output Parameter:
8235 . X       - The output vector
8236 
8237    Calling sequence of `funcs`:
8238 .vb
8239   void func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8240             const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8241             const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8242             PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8243 .ve
8244 +  dim          - The spatial dimension
8245 .  Nf           - The number of input fields
8246 .  NfAux        - The number of input auxiliary fields
8247 .  uOff         - The offset of each field in u[]
8248 .  uOff_x       - The offset of each field in u_x[]
8249 .  u            - The field values at this point in space
8250 .  u_t          - The field time derivative at this point in space (or NULL)
8251 .  u_x          - The field derivatives at this point in space
8252 .  aOff         - The offset of each auxiliary field in u[]
8253 .  aOff_x       - The offset of each auxiliary field in u_x[]
8254 .  a            - The auxiliary field values at this point in space
8255 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8256 .  a_x          - The auxiliary field derivatives at this point in space
8257 .  t            - The current time
8258 .  x            - The coordinates of this point
8259 .  numConstants - The number of constants
8260 .  constants    - The value of each constant
8261 -  f            - The value of the function at this point in space
8262 
8263   Note:
8264   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.
8265   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
8266   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8267   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8268 
8269   Level: intermediate
8270 
8271   Developer Notes:
8272   This API is specific to only particular usage of `DM`
8273 
8274   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8275 
8276 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8277 @*/
8278 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)
8279 {
8280   DM  dmIn;
8281   Vec localU, localX;
8282 
8283   PetscFunctionBegin;
8284   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8285   PetscCall(VecGetDM(U, &dmIn));
8286   PetscCall(DMGetLocalVector(dmIn, &localU));
8287   PetscCall(DMGetLocalVector(dm, &localX));
8288   PetscCall(VecSet(localX, 0.));
8289   PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU));
8290   PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU));
8291   PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8292   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8293   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8294   PetscCall(DMRestoreLocalVector(dm, &localX));
8295   PetscCall(DMRestoreLocalVector(dmIn, &localU));
8296   PetscFunctionReturn(PETSC_SUCCESS);
8297 }
8298 
8299 /*@C
8300   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.
8301 
8302   Not Collective
8303 
8304   Input Parameters:
8305 + dm      - The `DM`
8306 . time    - The time
8307 . label   - The `DMLabel` marking the portion of the domain boundary to output
8308 . numIds  - The number of label ids to use
8309 . ids     - The label ids to use for marking
8310 . Nc      - The number of components to set in the output, or `PETSC_DETERMINE` for all components
8311 . comps   - The components to set in the output, or `NULL` for all components
8312 . localU  - The input field vector
8313 . funcs   - The functions to evaluate, one per field
8314 - mode    - The insertion mode for values
8315 
8316   Output Parameter:
8317 . localX  - The output vector
8318 
8319    Calling sequence of `funcs`:
8320 .vb
8321    void funcs(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8322               const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8323               const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8324               PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8325 .ve
8326 +  dim          - The spatial dimension
8327 .  Nf           - The number of input fields
8328 .  NfAux        - The number of input auxiliary fields
8329 .  uOff         - The offset of each field in u[]
8330 .  uOff_x       - The offset of each field in u_x[]
8331 .  u            - The field values at this point in space
8332 .  u_t          - The field time derivative at this point in space (or NULL)
8333 .  u_x          - The field derivatives at this point in space
8334 .  aOff         - The offset of each auxiliary field in u[]
8335 .  aOff_x       - The offset of each auxiliary field in u_x[]
8336 .  a            - The auxiliary field values at this point in space
8337 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8338 .  a_x          - The auxiliary field derivatives at this point in space
8339 .  t            - The current time
8340 .  x            - The coordinates of this point
8341 .  n            - The face normal
8342 .  numConstants - The number of constants
8343 .  constants    - The value of each constant
8344 -  f            - The value of the function at this point in space
8345 
8346   Note:
8347   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.
8348   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
8349   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the
8350   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8351 
8352   Level: intermediate
8353 
8354   Developer Notes:
8355   This API is specific to only particular usage of `DM`
8356 
8357   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8358 
8359 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
8360 @*/
8361 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)
8362 {
8363   PetscFunctionBegin;
8364   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8365   PetscValidHeaderSpecific(localU, VEC_CLASSID, 8);
8366   PetscValidHeaderSpecific(localX, VEC_CLASSID, 11);
8367   PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
8368   PetscFunctionReturn(PETSC_SUCCESS);
8369 }
8370 
8371 /*@C
8372   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8373 
8374   Collective
8375 
8376   Input Parameters:
8377 + dm    - The `DM`
8378 . time  - The time
8379 . funcs - The 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 
8383   Output Parameter:
8384 . diff - The diff ||u - u_h||_2
8385 
8386   Level: developer
8387 
8388   Developer Notes:
8389   This API is specific to only particular usage of `DM`
8390 
8391   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8392 
8393 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8394 @*/
8395 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8396 {
8397   PetscFunctionBegin;
8398   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8399   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8400   PetscCall((dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff));
8401   PetscFunctionReturn(PETSC_SUCCESS);
8402 }
8403 
8404 /*@C
8405   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8406 
8407   Collective
8408 
8409   Input Parameters:
8410 + dm    - The `DM`
8411 , time  - The time
8412 . funcs - The gradient functions to evaluate for each field component
8413 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8414 . X     - The coefficient vector u_h, a global vector
8415 - n     - The vector to project along
8416 
8417   Output Parameter:
8418 . diff - The diff ||(grad u - grad u_h) . n||_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()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()`
8428 @*/
8429 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)
8430 {
8431   PetscFunctionBegin;
8432   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8433   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8434   PetscCall((dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff));
8435   PetscFunctionReturn(PETSC_SUCCESS);
8436 }
8437 
8438 /*@C
8439   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8440 
8441   Collective
8442 
8443   Input Parameters:
8444 + dm    - The `DM`
8445 . time  - The time
8446 . funcs - The functions to evaluate for each field component
8447 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8448 - X     - The coefficient vector u_h, a global vector
8449 
8450   Output Parameter:
8451 . diff - The array of differences, ||u^f - u^f_h||_2
8452 
8453   Level: developer
8454 
8455   Developer Notes:
8456   This API is specific to only particular usage of `DM`
8457 
8458   The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation.
8459 
8460 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
8461 @*/
8462 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8463 {
8464   PetscFunctionBegin;
8465   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8466   PetscValidHeaderSpecific(X, VEC_CLASSID, 5);
8467   PetscCall((dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff));
8468   PetscFunctionReturn(PETSC_SUCCESS);
8469 }
8470 
8471 /*@C
8472  DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors
8473 
8474  Not Collective
8475 
8476  Input Parameter:
8477 .  dm    - The `DM`
8478 
8479  Output Parameters:
8480 +  nranks - the number of neighbours
8481 -  ranks - the neighbors ranks
8482 
8483  Note:
8484  Do not free the array, it is freed when the `DM` is destroyed.
8485 
8486  Level: beginner
8487 
8488  .seealso: `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
8489 @*/
8490 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[])
8491 {
8492   PetscFunctionBegin;
8493   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8494   PetscCall((dm->ops->getneighbors)(dm, nranks, ranks));
8495   PetscFunctionReturn(PETSC_SUCCESS);
8496 }
8497 
8498 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
8499 
8500 /*
8501     Converts the input vector to a ghosted vector and then calls the standard coloring code.
8502     This has be a different function because it requires DM which is not defined in the Mat library
8503 */
8504 PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx)
8505 {
8506   PetscFunctionBegin;
8507   if (coloring->ctype == IS_COLORING_LOCAL) {
8508     Vec x1local;
8509     DM  dm;
8510     PetscCall(MatGetDM(J, &dm));
8511     PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM");
8512     PetscCall(DMGetLocalVector(dm, &x1local));
8513     PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local));
8514     PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local));
8515     x1 = x1local;
8516   }
8517   PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx));
8518   if (coloring->ctype == IS_COLORING_LOCAL) {
8519     DM dm;
8520     PetscCall(MatGetDM(J, &dm));
8521     PetscCall(DMRestoreLocalVector(dm, &x1));
8522   }
8523   PetscFunctionReturn(PETSC_SUCCESS);
8524 }
8525 
8526 /*@
8527     MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring
8528 
8529     Input Parameter:
8530 .    coloring - the `MatFDColoring` object
8531 
8532     Developer Note:
8533     this routine exists because the PETSc `Mat` library does not know about the `DM` objects
8534 
8535     Level: advanced
8536 
8537 .seealso: `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
8538 @*/
8539 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring)
8540 {
8541   PetscFunctionBegin;
8542   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
8543   PetscFunctionReturn(PETSC_SUCCESS);
8544 }
8545 
8546 /*@
8547     DMGetCompatibility - determine if two `DM`s are compatible
8548 
8549     Collective
8550 
8551     Input Parameters:
8552 +    dm1 - the first `DM`
8553 -    dm2 - the second `DM`
8554 
8555     Output Parameters:
8556 +    compatible - whether or not the two `DM`s are compatible
8557 -    set - whether or not the compatible value was actually determined and set
8558 
8559     Level: advanced
8560 
8561     Notes:
8562     Two `DM`s are deemed compatible if they represent the same parallel decomposition
8563     of the same topology. This implies that the section (field data) on one
8564     "makes sense" with respect to the topology and parallel decomposition of the other.
8565     Loosely speaking, compatible `DM`s represent the same domain and parallel
8566     decomposition, but hold different data.
8567 
8568     Typically, one would confirm compatibility if intending to simultaneously iterate
8569     over a pair of vectors obtained from different `DM`s.
8570 
8571     For example, two `DMDA` objects are compatible if they have the same local
8572     and global sizes and the same stencil width. They can have different numbers
8573     of degrees of freedom per node. Thus, one could use the node numbering from
8574     either `DM` in bounds for a loop over vectors derived from either `DM`.
8575 
8576     Consider the operation of summing data living on a 2-dof `DMDA` to data living
8577     on a 1-dof `DMDA`, which should be compatible, as in the following snippet.
8578 .vb
8579   ...
8580   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
8581   if (set && compatible)  {
8582     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
8583     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
8584     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
8585     for (j=y; j<y+n; ++j) {
8586       for (i=x; i<x+m, ++i) {
8587         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
8588       }
8589     }
8590     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
8591     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
8592   } else {
8593     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
8594   }
8595   ...
8596 .ve
8597 
8598     Checking compatibility might be expensive for a given implementation of `DM`,
8599     or might be impossible to unambiguously confirm or deny. For this reason,
8600     this function may decline to determine compatibility, and hence users should
8601     always check the "set" output parameter.
8602 
8603     A `DM` is always compatible with itself.
8604 
8605     In the current implementation, `DM`s which live on "unequal" communicators
8606     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
8607     incompatible.
8608 
8609     This function is labeled "Collective," as information about all subdomains
8610     is required on each rank. However, in `DM` implementations which store all this
8611     information locally, this function may be merely "Logically Collective".
8612 
8613     Developer Note:
8614     Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B
8615     iff B is compatible with A. Thus, this function checks the implementations
8616     of both dm and dmc (if they are of different types), attempting to determine
8617     compatibility. It is left to `DM` implementers to ensure that symmetry is
8618     preserved. The simplest way to do this is, when implementing type-specific
8619     logic for this function, is to check for existing logic in the implementation
8620     of other `DM` types and let *set = PETSC_FALSE if found.
8621 
8622 .seealso: `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
8623 @*/
8624 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set)
8625 {
8626   PetscMPIInt compareResult;
8627   DMType      type, type2;
8628   PetscBool   sameType;
8629 
8630   PetscFunctionBegin;
8631   PetscValidHeaderSpecific(dm1, DM_CLASSID, 1);
8632   PetscValidHeaderSpecific(dm2, DM_CLASSID, 2);
8633 
8634   /* Declare a DM compatible with itself */
8635   if (dm1 == dm2) {
8636     *set        = PETSC_TRUE;
8637     *compatible = PETSC_TRUE;
8638     PetscFunctionReturn(PETSC_SUCCESS);
8639   }
8640 
8641   /* Declare a DM incompatible with a DM that lives on an "unequal"
8642      communicator. Note that this does not preclude compatibility with
8643      DMs living on "congruent" or "similar" communicators, but this must be
8644      determined by the implementation-specific logic */
8645   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult));
8646   if (compareResult == MPI_UNEQUAL) {
8647     *set        = PETSC_TRUE;
8648     *compatible = PETSC_FALSE;
8649     PetscFunctionReturn(PETSC_SUCCESS);
8650   }
8651 
8652   /* Pass to the implementation-specific routine, if one exists. */
8653   if (dm1->ops->getcompatibility) {
8654     PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set);
8655     if (*set) PetscFunctionReturn(PETSC_SUCCESS);
8656   }
8657 
8658   /* If dm1 and dm2 are of different types, then attempt to check compatibility
8659      with an implementation of this function from dm2 */
8660   PetscCall(DMGetType(dm1, &type));
8661   PetscCall(DMGetType(dm2, &type2));
8662   PetscCall(PetscStrcmp(type, type2, &sameType));
8663   if (!sameType && dm2->ops->getcompatibility) {
8664     PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */
8665   } else {
8666     *set = PETSC_FALSE;
8667   }
8668   PetscFunctionReturn(PETSC_SUCCESS);
8669 }
8670 
8671 /*@C
8672   DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance.
8673 
8674   Logically Collective
8675 
8676   Input Parameters:
8677 + DM - the `DM`
8678 . f - the monitor function
8679 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired)
8680 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`)
8681 
8682   Options Database Key:
8683 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but
8684                             does not cancel those set via the options database.
8685 
8686   Note:
8687   Several different monitoring routines may be set by calling
8688   `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the
8689   order in which they were set.
8690 
8691   Fortran Note:
8692   Only a single monitor function can be set for each `DM` object
8693 
8694   Developer Note:
8695   This API has a generic name but seems specific to a very particular aspect of the use of `DM`
8696 
8697   Level: intermediate
8698 
8699 .seealso: `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8700 @*/
8701 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **))
8702 {
8703   PetscInt m;
8704 
8705   PetscFunctionBegin;
8706   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8707   for (m = 0; m < dm->numbermonitors; ++m) {
8708     PetscBool identical;
8709 
8710     PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
8711     if (identical) PetscFunctionReturn(PETSC_SUCCESS);
8712   }
8713   PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
8714   dm->monitor[dm->numbermonitors]          = f;
8715   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
8716   dm->monitorcontext[dm->numbermonitors++] = (void *)mctx;
8717   PetscFunctionReturn(PETSC_SUCCESS);
8718 }
8719 
8720 /*@
8721   DMMonitorCancel - Clears all the monitor functions for a `DM` object.
8722 
8723   Logically Collective
8724 
8725   Input Parameter:
8726 . dm - the DM
8727 
8728   Options Database Key:
8729 . -dm_monitor_cancel - cancels all monitors that have been hardwired
8730   into a code by calls to `DMonitorSet()`, but does not cancel those
8731   set via the options database
8732 
8733   Note:
8734   There is no way to clear one specific monitor from a `DM` object.
8735 
8736   Level: intermediate
8737 
8738 .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()`
8739 @*/
8740 PetscErrorCode DMMonitorCancel(DM dm)
8741 {
8742   PetscInt m;
8743 
8744   PetscFunctionBegin;
8745   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8746   for (m = 0; m < dm->numbermonitors; ++m) {
8747     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
8748   }
8749   dm->numbermonitors = 0;
8750   PetscFunctionReturn(PETSC_SUCCESS);
8751 }
8752 
8753 /*@C
8754   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
8755 
8756   Collective
8757 
8758   Input Parameters:
8759 + dm   - `DM` object you wish to monitor
8760 . name - the monitor type one is seeking
8761 . help - message indicating what monitoring is done
8762 . manual - manual page for the monitor
8763 . monitor - the monitor function
8764 - 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
8765 
8766   Output Parameter:
8767 . flg - Flag set if the monitor was created
8768 
8769   Level: developer
8770 
8771 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
8772           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
8773           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
8774           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
8775           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
8776           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
8777           `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()`
8778 @*/
8779 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
8780 {
8781   PetscViewer       viewer;
8782   PetscViewerFormat format;
8783 
8784   PetscFunctionBegin;
8785   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8786   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg));
8787   if (*flg) {
8788     PetscViewerAndFormat *vf;
8789 
8790     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
8791     PetscCall(PetscObjectDereference((PetscObject)viewer));
8792     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
8793     PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy));
8794   }
8795   PetscFunctionReturn(PETSC_SUCCESS);
8796 }
8797 
8798 /*@
8799    DMMonitor - runs the user provided monitor routines, if they exist
8800 
8801    Collective
8802 
8803    Input Parameter:
8804 .  dm - The `DM`
8805 
8806    Level: developer
8807 
8808    Question:
8809    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
8810    since some `DM` have no concept of discretization
8811 
8812 .seealso: `DMMonitorSet()`, `DMMonitorSetFromOptions()`
8813 @*/
8814 PetscErrorCode DMMonitor(DM dm)
8815 {
8816   PetscInt m;
8817 
8818   PetscFunctionBegin;
8819   if (!dm) PetscFunctionReturn(PETSC_SUCCESS);
8820   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8821   for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
8822   PetscFunctionReturn(PETSC_SUCCESS);
8823 }
8824 
8825 /*@
8826   DMComputeError - Computes the error assuming the user has provided the exact solution functions
8827 
8828   Collective
8829 
8830   Input Parameters:
8831 + dm     - The `DM`
8832 - sol    - The solution vector
8833 
8834   Input/Output Parameter:
8835 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output
8836            contains the error in each field
8837 
8838   Output Parameter:
8839 . errorVec - A vector to hold the cellwise error (may be `NULL`)
8840 
8841   Level: developer
8842 
8843   Note:
8844   The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`.
8845 
8846 .seealso: `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
8847 @*/
8848 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
8849 {
8850   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
8851   void    **ctxs;
8852   PetscReal time;
8853   PetscInt  Nf, f, Nds, s;
8854 
8855   PetscFunctionBegin;
8856   PetscCall(DMGetNumFields(dm, &Nf));
8857   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
8858   PetscCall(DMGetNumDS(dm, &Nds));
8859   for (s = 0; s < Nds; ++s) {
8860     PetscDS         ds;
8861     DMLabel         label;
8862     IS              fieldIS;
8863     const PetscInt *fields;
8864     PetscInt        dsNf;
8865 
8866     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL));
8867     PetscCall(PetscDSGetNumFields(ds, &dsNf));
8868     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
8869     for (f = 0; f < dsNf; ++f) {
8870       const PetscInt field = fields[f];
8871       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
8872     }
8873     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
8874   }
8875   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);
8876   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
8877   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
8878   if (errorVec) {
8879     DM             edm;
8880     DMPolytopeType ct;
8881     PetscBool      simplex;
8882     PetscInt       dim, cStart, Nf;
8883 
8884     PetscCall(DMClone(dm, &edm));
8885     PetscCall(DMGetDimension(edm, &dim));
8886     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
8887     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
8888     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE;
8889     PetscCall(DMGetNumFields(dm, &Nf));
8890     for (f = 0; f < Nf; ++f) {
8891       PetscFE         fe, efe;
8892       PetscQuadrature q;
8893       const char     *name;
8894 
8895       PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe));
8896       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
8897       PetscCall(PetscObjectGetName((PetscObject)fe, &name));
8898       PetscCall(PetscObjectSetName((PetscObject)efe, name));
8899       PetscCall(PetscFEGetQuadrature(fe, &q));
8900       PetscCall(PetscFESetQuadrature(efe, q));
8901       PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe));
8902       PetscCall(PetscFEDestroy(&efe));
8903     }
8904     PetscCall(DMCreateDS(edm));
8905 
8906     PetscCall(DMCreateGlobalVector(edm, errorVec));
8907     PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error"));
8908     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
8909     PetscCall(DMDestroy(&edm));
8910   }
8911   PetscCall(PetscFree2(exactSol, ctxs));
8912   PetscFunctionReturn(PETSC_SUCCESS);
8913 }
8914 
8915 /*@
8916   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM`
8917 
8918   Not Collective
8919 
8920   Input Parameter:
8921 . dm     - The `DM`
8922 
8923   Output Parameter:
8924 . numAux - The number of auxiliary data vectors
8925 
8926   Level: advanced
8927 
8928 .seealso: `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
8929 @*/
8930 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
8931 {
8932   PetscFunctionBegin;
8933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8934   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
8935   PetscFunctionReturn(PETSC_SUCCESS);
8936 }
8937 
8938 /*@
8939   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
8940 
8941   Not Collective
8942 
8943   Input Parameters:
8944 + dm     - The `DM`
8945 . label  - The `DMLabel`
8946 . value  - The label value indicating the region
8947 - part   - The equation part, or 0 if unused
8948 
8949   Output Parameter:
8950 . aux    - The `Vec` holding auxiliary field data
8951 
8952   Note:
8953   If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
8954 
8955   Level: advanced
8956 
8957 .seealso: `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()`
8958 @*/
8959 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
8960 {
8961   PetscHashAuxKey key, wild = {NULL, 0, 0};
8962   PetscBool       has;
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(PetscHMapAuxHas(dm->auxData, key, &has));
8971   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux));
8972   else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
8973   PetscFunctionReturn(PETSC_SUCCESS);
8974 }
8975 
8976 /*@
8977   DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part
8978 
8979   Not Collective because auxiliary vectors are not parallel
8980 
8981   Input Parameters:
8982 + dm     - The `DM`
8983 . label  - The `DMLabel`
8984 . value  - The label value indicating the region
8985 . part   - The equation part, or 0 if unused
8986 - aux    - The `Vec` holding auxiliary field data
8987 
8988   Level: advanced
8989 
8990 .seealso: `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()`
8991 @*/
8992 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
8993 {
8994   Vec             old;
8995   PetscHashAuxKey key;
8996 
8997   PetscFunctionBegin;
8998   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8999   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9000   key.label = label;
9001   key.value = value;
9002   key.part  = part;
9003   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9004   PetscCall(PetscObjectReference((PetscObject)aux));
9005   PetscCall(PetscObjectDereference((PetscObject)old));
9006   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9007   else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9008   PetscFunctionReturn(PETSC_SUCCESS);
9009 }
9010 
9011 /*@C
9012   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM`
9013 
9014   Not Collective
9015 
9016   Input Parameter:
9017 . dm      - The `DM`
9018 
9019   Output Parameters:
9020 + labels  - The `DMLabel`s for each `Vec`
9021 . values  - The label values for each `Vec`
9022 - parts   - The equation parts for each `Vec`
9023 
9024   Note:
9025   The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`.
9026 
9027   Level: advanced
9028 
9029 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMSetAuxiliaryVec()`, DMCopyAuxiliaryVec()`
9030 @*/
9031 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9032 {
9033   PetscHashAuxKey *keys;
9034   PetscInt         n, i, off = 0;
9035 
9036   PetscFunctionBegin;
9037   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9038   PetscValidPointer(labels, 2);
9039   PetscValidIntPointer(values, 3);
9040   PetscValidIntPointer(parts, 4);
9041   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9042   PetscCall(PetscMalloc1(n, &keys));
9043   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9044   for (i = 0; i < n; ++i) {
9045     labels[i] = keys[i].label;
9046     values[i] = keys[i].value;
9047     parts[i]  = keys[i].part;
9048   }
9049   PetscCall(PetscFree(keys));
9050   PetscFunctionReturn(PETSC_SUCCESS);
9051 }
9052 
9053 /*@
9054   DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM`
9055 
9056   Not Collective
9057 
9058   Input Parameter:
9059 . dm    - The `DM`
9060 
9061   Output Parameter:
9062 . dmNew - The new `DM`, now with the same auxiliary data
9063 
9064   Level: advanced
9065 
9066   Note:
9067   This is a shallow copy of the auxiliary vectors
9068 
9069 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9070 @*/
9071 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9072 {
9073   PetscFunctionBegin;
9074   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9075   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9076   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9077   PetscFunctionReturn(PETSC_SUCCESS);
9078 }
9079 
9080 /*@C
9081   DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9082 
9083   Not Collective
9084 
9085   Input Parameters:
9086 + ct         - The `DMPolytopeType`
9087 . sourceCone - The source arrangement of faces
9088 - targetCone - The target arrangement of faces
9089 
9090   Output Parameters:
9091 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9092 - found - Flag indicating that a suitable orientation was found
9093 
9094   Level: advanced
9095 
9096   Note:
9097   An arrangement is a face order combined with an orientation for each face
9098 
9099   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
9100   that labels each arrangement (face ordering plus orientation for each face).
9101 
9102   See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement
9103 
9104 .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()`
9105 @*/
9106 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9107 {
9108   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9109   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
9110   PetscInt       o, c;
9111 
9112   PetscFunctionBegin;
9113   if (!nO) {
9114     *ornt  = 0;
9115     *found = PETSC_TRUE;
9116     PetscFunctionReturn(PETSC_SUCCESS);
9117   }
9118   for (o = -nO; o < nO; ++o) {
9119     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
9120 
9121     for (c = 0; c < cS; ++c)
9122       if (sourceCone[arr[c * 2]] != targetCone[c]) break;
9123     if (c == cS) {
9124       *ornt = o;
9125       break;
9126     }
9127   }
9128   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9129   PetscFunctionReturn(PETSC_SUCCESS);
9130 }
9131 
9132 /*@C
9133   DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement
9134 
9135   Not Collective
9136 
9137   Input Parameters:
9138 + ct         - The `DMPolytopeType`
9139 . sourceCone - The source arrangement of faces
9140 - targetCone - The target arrangement of faces
9141 
9142   Output Parameter:
9143 . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9144 
9145   Level: advanced
9146 
9147   Note:
9148   This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found.
9149 
9150   Developer Note:
9151   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found
9152 
9153 .seealso: `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()`
9154 @*/
9155 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9156 {
9157   PetscBool found;
9158 
9159   PetscFunctionBegin;
9160   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9161   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9162   PetscFunctionReturn(PETSC_SUCCESS);
9163 }
9164 
9165 /*@C
9166   DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9167 
9168   Not Collective
9169 
9170   Input Parameters:
9171 + ct         - The `DMPolytopeType`
9172 . sourceVert - The source arrangement of vertices
9173 - targetVert - The target arrangement of vertices
9174 
9175   Output Parameters:
9176 + ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9177 - found - Flag indicating that a suitable orientation was found
9178 
9179   Level: advanced
9180 
9181   Note:
9182   An arrangement is a vertex order
9183 
9184   Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2
9185   that labels each arrangement (vertex ordering).
9186 
9187   See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement
9188 
9189 .seealso: `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()`
9190 @*/
9191 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9192 {
9193   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9194   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2;
9195   PetscInt       o, c;
9196 
9197   PetscFunctionBegin;
9198   if (!nO) {
9199     *ornt  = 0;
9200     *found = PETSC_TRUE;
9201     PetscFunctionReturn(PETSC_SUCCESS);
9202   }
9203   for (o = -nO; o < nO; ++o) {
9204     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
9205 
9206     for (c = 0; c < cS; ++c)
9207       if (sourceVert[arr[c]] != targetVert[c]) break;
9208     if (c == cS) {
9209       *ornt = o;
9210       break;
9211     }
9212   }
9213   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9214   PetscFunctionReturn(PETSC_SUCCESS);
9215 }
9216 
9217 /*@C
9218   DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement
9219 
9220   Not Collective
9221 
9222   Input Parameters:
9223 + ct         - The `DMPolytopeType`
9224 . sourceCone - The source arrangement of vertices
9225 - targetCone - The target arrangement of vertices
9226 
9227   Output Parameter:
9228 . ornt  - The orientation (transformation) which will take the source arrangement to the target arrangement
9229 
9230   Level: advanced
9231 
9232   Note:
9233   This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible.
9234 
9235   Developer Note:
9236   It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found
9237 
9238 .seealso: `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
9239 @*/
9240 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9241 {
9242   PetscBool found;
9243 
9244   PetscFunctionBegin;
9245   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
9246   PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9247   PetscFunctionReturn(PETSC_SUCCESS);
9248 }
9249 
9250 /*@C
9251   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
9252 
9253   Not Collective
9254 
9255   Input Parameters:
9256 + ct    - The `DMPolytopeType`
9257 - point - Coordinates of the point
9258 
9259   Output Parameter:
9260 . inside  - Flag indicating whether the point is inside the reference cell of given type
9261 
9262   Level: advanced
9263 
9264 .seealso: `DM`, `DMPolytopeType`, `DMLocatePoints()`
9265 @*/
9266 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
9267 {
9268   PetscReal sum = 0.0;
9269   PetscInt  d;
9270 
9271   PetscFunctionBegin;
9272   *inside = PETSC_TRUE;
9273   switch (ct) {
9274   case DM_POLYTOPE_TRIANGLE:
9275   case DM_POLYTOPE_TETRAHEDRON:
9276     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
9277       if (point[d] < -1.0) {
9278         *inside = PETSC_FALSE;
9279         break;
9280       }
9281       sum += point[d];
9282     }
9283     if (sum > PETSC_SMALL) {
9284       *inside = PETSC_FALSE;
9285       break;
9286     }
9287     break;
9288   case DM_POLYTOPE_QUADRILATERAL:
9289   case DM_POLYTOPE_HEXAHEDRON:
9290     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
9291       if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) {
9292         *inside = PETSC_FALSE;
9293         break;
9294       }
9295     break;
9296   default:
9297     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
9298   }
9299   PetscFunctionReturn(PETSC_SUCCESS);
9300 }
9301