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