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