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