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