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