xref: /petsc/src/dm/interface/dm.c (revision 40cbb1a031ea8f2be4fe2b92dc842b003ad37be3)
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 PetscErrorCode DMCompleteBCLabels_Internal(DM dm)
5184 {
5185   DM           plex;
5186   DMLabel     *labels, *glabels;
5187   const char **names;
5188   char        *sendNames, *recvNames;
5189   PetscInt     Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m;
5190   size_t       len;
5191   MPI_Comm     comm;
5192   PetscMPIInt  rank, size, p, *counts, *displs;
5193 
5194   PetscFunctionBegin;
5195   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
5196   PetscCallMPI(MPI_Comm_size(comm, &size));
5197   PetscCallMPI(MPI_Comm_rank(comm, &rank));
5198   PetscCall(DMGetNumDS(dm, &Nds));
5199   for (s = 0; s < Nds; ++s) {
5200     PetscDS  dsBC;
5201     PetscInt numBd;
5202 
5203     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC));
5204     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5205     maxLabels += numBd;
5206   }
5207   PetscCall(PetscCalloc1(maxLabels, &labels));
5208   /* Get list of labels to be completed */
5209   for (s = 0; s < Nds; ++s) {
5210     PetscDS  dsBC;
5211     PetscInt numBd, bd;
5212 
5213     PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC));
5214     PetscCall(PetscDSGetNumBoundary(dsBC, &numBd));
5215     for (bd = 0; bd < numBd; ++bd) {
5216       DMLabel      label;
5217       PetscInt     field;
5218       PetscObject  obj;
5219       PetscClassId id;
5220 
5221       PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
5222       PetscCall(DMGetField(dm, field, NULL, &obj));
5223       PetscCall(PetscObjectGetClassId(obj, &id));
5224       if (!(id == PETSCFE_CLASSID) || !label) continue;
5225       for (l = 0; l < Nl; ++l) if (labels[l] == label) break;
5226       if (l == Nl) labels[Nl++] = label;
5227     }
5228   }
5229   /* Get label names */
5230   PetscCall(PetscMalloc1(Nl, &names));
5231   for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject) labels[l], &names[l]));
5232   for (l = 0; l < Nl; ++l) {PetscCall(PetscStrlen(names[l], &len)); maxLen = PetscMax(maxLen, (PetscInt) len+2);}
5233   PetscCall(PetscFree(labels));
5234   PetscCallMPI(MPI_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm));
5235   PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames));
5236   for (l = 0; l < Nl; ++l) PetscCall(PetscStrcpy(&sendNames[gmaxLen*l], names[l]));
5237   PetscCall(PetscFree(names));
5238   /* Put all names on all processes */
5239   PetscCall(PetscCalloc2(size, &counts, size+1, &displs));
5240   PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm));
5241   for (p = 0; p < size; ++p) displs[p+1] = displs[p] + counts[p];
5242   gNl = displs[size];
5243   for (p = 0; p < size; ++p) {counts[p] *= gmaxLen; displs[p] *= gmaxLen;}
5244   PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels));
5245   PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm));
5246   PetscCall(PetscFree2(counts, displs));
5247   PetscCall(PetscFree(sendNames));
5248   for (l = 0, gl = 0; l < gNl; ++l) {
5249     PetscCall(DMGetLabel(dm, &recvNames[l*gmaxLen], &glabels[gl]));
5250     PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l*gmaxLen], rank);
5251     for (m = 0; m < gl; ++m) if (glabels[m] == glabels[gl]) continue;
5252     PetscCall(DMConvert(dm, DMPLEX, &plex));
5253     PetscCall(DMPlexLabelComplete(plex, glabels[gl]));
5254     PetscCall(DMDestroy(&plex));
5255     ++gl;
5256   }
5257   PetscCall(PetscFree2(recvNames, glabels));
5258   PetscFunctionReturn(0);
5259 }
5260 
5261 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5262 {
5263   DMSpace       *tmpd;
5264   PetscInt       Nds = dm->Nds, s;
5265 
5266   PetscFunctionBegin;
5267   if (Nds >= NdsNew) PetscFunctionReturn(0);
5268   PetscCall(PetscMalloc1(NdsNew, &tmpd));
5269   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5270   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5271   PetscCall(PetscFree(dm->probs));
5272   dm->Nds   = NdsNew;
5273   dm->probs = tmpd;
5274   PetscFunctionReturn(0);
5275 }
5276 
5277 /*@
5278   DMGetNumDS - Get the number of discrete systems in the DM
5279 
5280   Not collective
5281 
5282   Input Parameter:
5283 . dm - The DM
5284 
5285   Output Parameter:
5286 . Nds - The number of PetscDS objects
5287 
5288   Level: intermediate
5289 
5290 .seealso: `DMGetDS()`, `DMGetCellDS()`
5291 @*/
5292 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5293 {
5294   PetscFunctionBegin;
5295   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5296   PetscValidIntPointer(Nds, 2);
5297   *Nds = dm->Nds;
5298   PetscFunctionReturn(0);
5299 }
5300 
5301 /*@
5302   DMClearDS - Remove all discrete systems from the DM
5303 
5304   Logically collective on dm
5305 
5306   Input Parameter:
5307 . dm - The DM
5308 
5309   Level: intermediate
5310 
5311 .seealso: `DMGetNumDS()`, `DMGetDS()`, `DMSetField()`
5312 @*/
5313 PetscErrorCode DMClearDS(DM dm)
5314 {
5315   PetscInt       s;
5316 
5317   PetscFunctionBegin;
5318   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5319   for (s = 0; s < dm->Nds; ++s) {
5320     PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5321     PetscCall(DMLabelDestroy(&dm->probs[s].label));
5322     PetscCall(ISDestroy(&dm->probs[s].fields));
5323   }
5324   PetscCall(PetscFree(dm->probs));
5325   dm->probs = NULL;
5326   dm->Nds   = 0;
5327   PetscFunctionReturn(0);
5328 }
5329 
5330 /*@
5331   DMGetDS - Get the default PetscDS
5332 
5333   Not collective
5334 
5335   Input Parameter:
5336 . dm    - The DM
5337 
5338   Output Parameter:
5339 . prob - The default PetscDS
5340 
5341   Level: intermediate
5342 
5343 .seealso: `DMGetCellDS()`, `DMGetRegionDS()`
5344 @*/
5345 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5346 {
5347   PetscFunctionBeginHot;
5348   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5349   PetscValidPointer(prob, 2);
5350   if (dm->Nds <= 0) {
5351     PetscDS ds;
5352 
5353     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
5354     PetscCall(DMSetRegionDS(dm, NULL, NULL, ds));
5355     PetscCall(PetscDSDestroy(&ds));
5356   }
5357   *prob = dm->probs[0].ds;
5358   PetscFunctionReturn(0);
5359 }
5360 
5361 /*@
5362   DMGetCellDS - Get the PetscDS defined on a given cell
5363 
5364   Not collective
5365 
5366   Input Parameters:
5367 + dm    - The DM
5368 - point - Cell for the DS
5369 
5370   Output Parameter:
5371 . prob - The PetscDS defined on the given cell
5372 
5373   Level: developer
5374 
5375 .seealso: `DMGetDS()`, `DMSetRegionDS()`
5376 @*/
5377 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5378 {
5379   PetscDS        probDef = NULL;
5380   PetscInt       s;
5381 
5382   PetscFunctionBeginHot;
5383   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5384   PetscValidPointer(prob, 3);
5385   PetscCheck(point >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point);
5386   *prob = NULL;
5387   for (s = 0; s < dm->Nds; ++s) {
5388     PetscInt val;
5389 
5390     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5391     else {
5392       PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val));
5393       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5394     }
5395   }
5396   if (!*prob) *prob = probDef;
5397   PetscFunctionReturn(0);
5398 }
5399 
5400 /*@
5401   DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5402 
5403   Not collective
5404 
5405   Input Parameters:
5406 + dm    - The DM
5407 - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5408 
5409   Output Parameters:
5410 + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5411 - prob - The PetscDS defined on the given region, or NULL
5412 
5413   Note:
5414   If a non-NULL label is given, but there is no PetscDS on that specific label,
5415   the PetscDS for the full domain (if present) is returned. Returns with
5416   fields=NULL and prob=NULL if there is no PetscDS for the full domain.
5417 
5418   Level: advanced
5419 
5420 .seealso: `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5421 @*/
5422 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5423 {
5424   PetscInt Nds = dm->Nds, s;
5425 
5426   PetscFunctionBegin;
5427   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5428   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5429   if (fields) {PetscValidPointer(fields, 3); *fields = NULL;}
5430   if (ds)     {PetscValidPointer(ds, 4);     *ds     = NULL;}
5431   for (s = 0; s < Nds; ++s) {
5432     if (dm->probs[s].label == label || !dm->probs[s].label) {
5433       if (fields) *fields = dm->probs[s].fields;
5434       if (ds)     *ds     = dm->probs[s].ds;
5435       if (dm->probs[s].label) PetscFunctionReturn(0);
5436     }
5437   }
5438   PetscFunctionReturn(0);
5439 }
5440 
5441 /*@
5442   DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
5443 
5444   Collective on dm
5445 
5446   Input Parameters:
5447 + dm     - The DM
5448 . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5449 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5450 - prob   - The PetscDS defined on the given cell
5451 
5452   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5453   the fields argument is ignored.
5454 
5455   Level: advanced
5456 
5457 .seealso: `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()`
5458 @*/
5459 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5460 {
5461   PetscInt       Nds = dm->Nds, s;
5462 
5463   PetscFunctionBegin;
5464   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5465   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5466   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4);
5467   for (s = 0; s < Nds; ++s) {
5468     if (dm->probs[s].label == label) {
5469       PetscCall(PetscDSDestroy(&dm->probs[s].ds));
5470       dm->probs[s].ds = ds;
5471       PetscFunctionReturn(0);
5472     }
5473   }
5474   PetscCall(DMDSEnlarge_Static(dm, Nds+1));
5475   PetscCall(PetscObjectReference((PetscObject) label));
5476   PetscCall(PetscObjectReference((PetscObject) fields));
5477   PetscCall(PetscObjectReference((PetscObject) ds));
5478   if (!label) {
5479     /* Put the NULL label at the front, so it is returned as the default */
5480     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5481     Nds = 0;
5482   }
5483   dm->probs[Nds].label  = label;
5484   dm->probs[Nds].fields = fields;
5485   dm->probs[Nds].ds     = ds;
5486   PetscFunctionReturn(0);
5487 }
5488 
5489 /*@
5490   DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5491 
5492   Not collective
5493 
5494   Input Parameters:
5495 + dm  - The DM
5496 - num - The region number, in [0, Nds)
5497 
5498   Output Parameters:
5499 + label  - The region label, or NULL
5500 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5501 - ds     - The PetscDS defined on the given region, or NULL
5502 
5503   Level: advanced
5504 
5505 .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5506 @*/
5507 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5508 {
5509   PetscInt       Nds;
5510 
5511   PetscFunctionBegin;
5512   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5513   PetscCall(DMGetNumDS(dm, &Nds));
5514   PetscCheck((num >= 0) && (num < Nds),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5515   if (label) {
5516     PetscValidPointer(label, 3);
5517     *label = dm->probs[num].label;
5518   }
5519   if (fields) {
5520     PetscValidPointer(fields, 4);
5521     *fields = dm->probs[num].fields;
5522   }
5523   if (ds) {
5524     PetscValidPointer(ds, 5);
5525     *ds = dm->probs[num].ds;
5526   }
5527   PetscFunctionReturn(0);
5528 }
5529 
5530 /*@
5531   DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5532 
5533   Not collective
5534 
5535   Input Parameters:
5536 + dm     - The DM
5537 . num    - The region number, in [0, Nds)
5538 . label  - The region label, or NULL
5539 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5540 - ds     - The PetscDS defined on the given region, or NULL to prevent setting
5541 
5542   Level: advanced
5543 
5544 .seealso: `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5545 @*/
5546 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5547 {
5548   PetscInt       Nds;
5549 
5550   PetscFunctionBegin;
5551   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5552   if (label) {PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);}
5553   PetscCall(DMGetNumDS(dm, &Nds));
5554   PetscCheck((num >= 0) && (num < Nds),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds);
5555   PetscCall(PetscObjectReference((PetscObject) label));
5556   PetscCall(DMLabelDestroy(&dm->probs[num].label));
5557   dm->probs[num].label = label;
5558   if (fields) {
5559     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5560     PetscCall(PetscObjectReference((PetscObject) fields));
5561     PetscCall(ISDestroy(&dm->probs[num].fields));
5562     dm->probs[num].fields = fields;
5563   }
5564   if (ds) {
5565     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5566     PetscCall(PetscObjectReference((PetscObject) ds));
5567     PetscCall(PetscDSDestroy(&dm->probs[num].ds));
5568     dm->probs[num].ds = ds;
5569   }
5570   PetscFunctionReturn(0);
5571 }
5572 
5573 /*@
5574   DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5575 
5576   Not collective
5577 
5578   Input Parameters:
5579 + dm  - The DM
5580 - ds  - The PetscDS defined on the given region
5581 
5582   Output Parameter:
5583 . num - The region number, in [0, Nds), or -1 if not found
5584 
5585   Level: advanced
5586 
5587 .seealso: `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()`
5588 @*/
5589 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5590 {
5591   PetscInt       Nds, n;
5592 
5593   PetscFunctionBegin;
5594   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5595   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5596   PetscValidIntPointer(num, 3);
5597   PetscCall(DMGetNumDS(dm, &Nds));
5598   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5599   if (n >= Nds) *num = -1;
5600   else          *num = n;
5601   PetscFunctionReturn(0);
5602 }
5603 
5604 /*@C
5605   DMCreateFEDefault - Create a PetscFE based on the celltype for the mesh
5606 
5607   Not collective
5608 
5609   Input Parameters:
5610 + dm     - The DM
5611 . Nc     - The number of components for the field
5612 . prefix - The options prefix for the output PetscFE, or NULL
5613 - qorder - The quadrature order or PETSC_DETERMINE to use PetscSpace polynomial degree
5614 
5615   Output Parameter:
5616 . fem - The PetscFE
5617 
5618   Note: This is a convenience method that just calls PetscFECreateByCell() underneath.
5619 
5620   Level: intermediate
5621 
5622 .seealso: `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()`
5623 @*/
5624 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem)
5625 {
5626   DMPolytopeType ct;
5627   PetscInt       dim, cStart;
5628 
5629   PetscFunctionBegin;
5630   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5631   PetscValidLogicalCollectiveInt(dm, Nc, 2);
5632   if (prefix) PetscValidCharPointer(prefix, 3);
5633   PetscValidLogicalCollectiveInt(dm, qorder, 4);
5634   PetscValidPointer(fem, 5);
5635   PetscCall(DMGetDimension(dm, &dim));
5636   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
5637   PetscCall(DMPlexGetCellType(dm, cStart, &ct));
5638   PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem));
5639   PetscFunctionReturn(0);
5640 }
5641 
5642 /*@
5643   DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5644 
5645   Collective on dm
5646 
5647   Input Parameter:
5648 . dm - The DM
5649 
5650   Options Database Keys:
5651 . -dm_petscds_view - View all the PetscDS objects in this DM
5652 
5653   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5654 
5655   Level: intermediate
5656 
5657 .seealso: `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
5658 @*/
5659 PetscErrorCode DMCreateDS(DM dm)
5660 {
5661   MPI_Comm       comm;
5662   PetscDS        dsDef;
5663   DMLabel       *labelSet;
5664   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k;
5665   PetscBool      doSetup = PETSC_TRUE, flg;
5666 
5667   PetscFunctionBegin;
5668   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5669   if (!dm->fields) PetscFunctionReturn(0);
5670   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
5671   PetscCall(DMGetCoordinateDim(dm, &dE));
5672   /* Determine how many regions we have */
5673   PetscCall(PetscMalloc1(Nf, &labelSet));
5674   Nl   = 0;
5675   Ndef = 0;
5676   for (f = 0; f < Nf; ++f) {
5677     DMLabel  label = dm->fields[f].label;
5678     PetscInt l;
5679 
5680 #ifdef PETSC_HAVE_LIBCEED
5681     /* Move CEED context to discretizations */
5682     {
5683       PetscClassId id;
5684 
5685       PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id));
5686       if (id == PETSCFE_CLASSID) {
5687         Ceed ceed;
5688 
5689         PetscCall(DMGetCeed(dm, &ceed));
5690         PetscCall(PetscFESetCeed((PetscFE) dm->fields[f].disc, ceed));
5691       }
5692     }
5693 #endif
5694     if (!label) {++Ndef; continue;}
5695     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5696     if (l < Nl) continue;
5697     labelSet[Nl++] = label;
5698   }
5699   /* Create default DS if there are no labels to intersect with */
5700   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef));
5701   if (!dsDef && Ndef && !Nl) {
5702     IS        fields;
5703     PetscInt *fld, nf;
5704 
5705     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5706     PetscCheck(nf,comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS");
5707     PetscCall(PetscMalloc1(nf, &fld));
5708     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5709     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5710     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_"));
5711     PetscCall(ISSetType(fields, ISGENERAL));
5712     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5713 
5714     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5715     PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef));
5716     PetscCall(PetscDSDestroy(&dsDef));
5717     PetscCall(ISDestroy(&fields));
5718   }
5719   PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef));
5720   if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5721   /* Intersect labels with default fields */
5722   if (Ndef && Nl) {
5723     DM              plex;
5724     DMLabel         cellLabel;
5725     IS              fieldIS, allcellIS, defcellIS = NULL;
5726     PetscInt       *fields;
5727     const PetscInt *cells;
5728     PetscInt        depth, nf = 0, n, c;
5729 
5730     PetscCall(DMConvert(dm, DMPLEX, &plex));
5731     PetscCall(DMPlexGetDepth(plex, &depth));
5732     PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS));
5733     if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS));
5734     /* TODO This looks like it only works for one label */
5735     for (l = 0; l < Nl; ++l) {
5736       DMLabel label = labelSet[l];
5737       IS      pointIS;
5738 
5739       PetscCall(ISDestroy(&defcellIS));
5740       PetscCall(DMLabelGetStratumIS(label, 1, &pointIS));
5741       PetscCall(ISDifference(allcellIS, pointIS, &defcellIS));
5742       PetscCall(ISDestroy(&pointIS));
5743     }
5744     PetscCall(ISDestroy(&allcellIS));
5745 
5746     PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel));
5747     PetscCall(ISGetLocalSize(defcellIS, &n));
5748     PetscCall(ISGetIndices(defcellIS, &cells));
5749     for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1));
5750     PetscCall(ISRestoreIndices(defcellIS, &cells));
5751     PetscCall(ISDestroy(&defcellIS));
5752     PetscCall(DMPlexLabelComplete(plex, cellLabel));
5753 
5754     PetscCall(PetscMalloc1(Ndef, &fields));
5755     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5756     PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS));
5757     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_"));
5758     PetscCall(ISSetType(fieldIS, ISGENERAL));
5759     PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER));
5760 
5761     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef));
5762     PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef));
5763     PetscCall(PetscDSSetCoordinateDimension(dsDef, dE));
5764     PetscCall(DMLabelDestroy(&cellLabel));
5765     PetscCall(PetscDSDestroy(&dsDef));
5766     PetscCall(ISDestroy(&fieldIS));
5767     PetscCall(DMDestroy(&plex));
5768   }
5769   /* Create label DSes
5770      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5771   */
5772   /* TODO Should check that labels are disjoint */
5773   for (l = 0; l < Nl; ++l) {
5774     DMLabel   label = labelSet[l];
5775     PetscDS   ds;
5776     IS        fields;
5777     PetscInt *fld, nf;
5778 
5779     PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds));
5780     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5781     PetscCall(PetscMalloc1(nf, &fld));
5782     for (f = 0, nf  = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5783     PetscCall(ISCreate(PETSC_COMM_SELF, &fields));
5784     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_"));
5785     PetscCall(ISSetType(fields, ISGENERAL));
5786     PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER));
5787     PetscCall(DMSetRegionDS(dm, label, fields, ds));
5788     PetscCall(ISDestroy(&fields));
5789     PetscCall(PetscDSSetCoordinateDimension(ds, dE));
5790     {
5791       DMPolytopeType ct;
5792       PetscInt       lStart, lEnd;
5793       PetscBool      isCohesiveLocal = PETSC_FALSE, isCohesive;
5794 
5795       PetscCall(DMLabelGetBounds(label, &lStart, &lEnd));
5796       if (lStart >= 0) {
5797         PetscCall(DMPlexGetCellType(dm, lStart, &ct));
5798         switch (ct) {
5799           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5800           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5801           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5802           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5803             isCohesiveLocal = PETSC_TRUE;break;
5804           default: break;
5805         }
5806       }
5807       PetscCallMPI(MPI_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm));
5808       for (f = 0, nf  = 0; f < Nf; ++f) {
5809         if (label == dm->fields[f].label || !dm->fields[f].label) {
5810           if (label == dm->fields[f].label) {
5811             PetscCall(PetscDSSetDiscretization(ds, nf, NULL));
5812             PetscCall(PetscDSSetCohesive(ds, nf, isCohesive));
5813           }
5814           ++nf;
5815         }
5816       }
5817     }
5818     PetscCall(PetscDSDestroy(&ds));
5819   }
5820   PetscCall(PetscFree(labelSet));
5821   /* Set fields in DSes */
5822   for (s = 0; s < dm->Nds; ++s) {
5823     PetscDS         ds     = dm->probs[s].ds;
5824     IS              fields = dm->probs[s].fields;
5825     const PetscInt *fld;
5826     PetscInt        nf, dsnf;
5827     PetscBool       isCohesive;
5828 
5829     PetscCall(PetscDSGetNumFields(ds, &dsnf));
5830     PetscCall(PetscDSIsCohesive(ds, &isCohesive));
5831     PetscCall(ISGetLocalSize(fields, &nf));
5832     PetscCall(ISGetIndices(fields, &fld));
5833     for (f = 0; f < nf; ++f) {
5834       PetscObject  disc  = dm->fields[fld[f]].disc;
5835       PetscBool    isCohesiveField;
5836       PetscClassId id;
5837 
5838       /* Handle DS with no fields */
5839       if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField));
5840       /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */
5841       if (isCohesive && !isCohesiveField) PetscCall(PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc));
5842       PetscCall(PetscDSSetDiscretization(ds, f, disc));
5843       /* We allow people to have placeholder fields and construct the Section by hand */
5844       PetscCall(PetscObjectGetClassId(disc, &id));
5845       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5846     }
5847     PetscCall(ISRestoreIndices(fields, &fld));
5848   }
5849   /* Allow k-jet tabulation */
5850   PetscCall(PetscOptionsGetInt(NULL, ((PetscObject) dm)->prefix, "-dm_ds_jet_degree", &k, &flg));
5851   if (flg) {
5852     for (s = 0; s < dm->Nds; ++s) {
5853       PetscDS  ds = dm->probs[s].ds;
5854       PetscInt Nf, f;
5855 
5856       PetscCall(PetscDSGetNumFields(ds, &Nf));
5857       for (f = 0; f < Nf; ++f) PetscCall(PetscDSSetJetDegree(ds, f, k));
5858     }
5859   }
5860   /* Setup DSes */
5861   if (doSetup) {
5862     for (s = 0; s < dm->Nds; ++s) PetscCall(PetscDSSetUp(dm->probs[s].ds));
5863   }
5864   PetscFunctionReturn(0);
5865 }
5866 
5867 /*@
5868   DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.
5869 
5870   Collective on DM
5871 
5872   Input Parameters:
5873 + dm   - The DM
5874 - time - The time
5875 
5876   Output Parameters:
5877 + u    - The vector will be filled with exact solution values, or NULL
5878 - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL
5879 
5880   Note: The user must call PetscDSSetExactSolution() beforehand
5881 
5882   Level: developer
5883 
5884 .seealso: `PetscDSSetExactSolution()`
5885 @*/
5886 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5887 {
5888   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5889   void            **ectxs;
5890   PetscInt          Nf, Nds, s;
5891 
5892   PetscFunctionBegin;
5893   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5894   if (u)   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
5895   if (u_t) PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
5896   PetscCall(DMGetNumFields(dm, &Nf));
5897   PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs));
5898   PetscCall(DMGetNumDS(dm, &Nds));
5899   for (s = 0; s < Nds; ++s) {
5900     PetscDS         ds;
5901     DMLabel         label;
5902     IS              fieldIS;
5903     const PetscInt *fields, id = 1;
5904     PetscInt        dsNf, f;
5905 
5906     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
5907     PetscCall(PetscDSGetNumFields(ds, &dsNf));
5908     PetscCall(ISGetIndices(fieldIS, &fields));
5909     PetscCall(PetscArrayzero(exacts, Nf));
5910     PetscCall(PetscArrayzero(ectxs, Nf));
5911     if (u) {
5912       for (f = 0; f < dsNf; ++f) {
5913         const PetscInt field = fields[f];
5914         PetscCall(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]));
5915       }
5916       PetscCall(ISRestoreIndices(fieldIS, &fields));
5917       if (label) {
5918         PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u));
5919       } else {
5920         PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u));
5921       }
5922     }
5923     if (u_t) {
5924       PetscCall(PetscArrayzero(exacts, Nf));
5925       PetscCall(PetscArrayzero(ectxs, Nf));
5926       for (f = 0; f < dsNf; ++f) {
5927         const PetscInt field = fields[f];
5928         PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]));
5929       }
5930       PetscCall(ISRestoreIndices(fieldIS, &fields));
5931       if (label) {
5932         PetscCall(DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t));
5933       } else {
5934         PetscCall(DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t));
5935       }
5936     }
5937   }
5938   if (u) {
5939     PetscCall(PetscObjectSetName((PetscObject) u, "Exact Solution"));
5940     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) u, "exact_"));
5941   }
5942   if (u_t) {
5943     PetscCall(PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative"));
5944     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_"));
5945   }
5946   PetscCall(PetscFree2(exacts, ectxs));
5947   PetscFunctionReturn(0);
5948 }
5949 
5950 PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds)
5951 {
5952   PetscDS        dsNew;
5953   DSBoundary     b;
5954   PetscInt       cdim, Nf, f, d;
5955   PetscBool      isCohesive;
5956   void          *ctx;
5957 
5958   PetscFunctionBegin;
5959   PetscCall(PetscDSCreate(PetscObjectComm((PetscObject) ds), &dsNew));
5960   PetscCall(PetscDSCopyConstants(ds, dsNew));
5961   PetscCall(PetscDSCopyExactSolutions(ds, dsNew));
5962   PetscCall(PetscDSSelectDiscretizations(ds, PETSC_DETERMINE, NULL, dsNew));
5963   PetscCall(PetscDSCopyEquations(ds, dsNew));
5964   PetscCall(PetscDSGetNumFields(ds, &Nf));
5965   for (f = 0; f < Nf; ++f) {
5966     PetscCall(PetscDSGetContext(ds, f, &ctx));
5967     PetscCall(PetscDSSetContext(dsNew, f, ctx));
5968     PetscCall(PetscDSGetCohesive(ds, f, &isCohesive));
5969     PetscCall(PetscDSSetCohesive(dsNew, f, isCohesive));
5970     PetscCall(PetscDSGetJetDegree(ds, f, &d));
5971     PetscCall(PetscDSSetJetDegree(dsNew, f, d));
5972   }
5973   if (Nf) {
5974     PetscCall(PetscDSGetCoordinateDimension(ds, &cdim));
5975     PetscCall(PetscDSSetCoordinateDimension(dsNew, cdim));
5976   }
5977   PetscCall(PetscDSCopyBoundary(ds, PETSC_DETERMINE, NULL, dsNew));
5978   for (b = dsNew->boundary; b; b = b->next) {
5979     PetscCall(DMGetLabel(dm, b->lname, &b->label));
5980     /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5981     //PetscCheck(b->label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Label %s missing in new DM", name);
5982   }
5983 
5984   PetscCall(DMSetRegionDS(dm, label, fields, dsNew));
5985   PetscCall(PetscDSDestroy(&dsNew));
5986   PetscFunctionReturn(0);
5987 }
5988 
5989 /*@
5990   DMCopyDS - Copy the discrete systems for the DM into another DM
5991 
5992   Collective on dm
5993 
5994   Input Parameter:
5995 . dm - The DM
5996 
5997   Output Parameter:
5998 . newdm - The DM
5999 
6000   Level: advanced
6001 
6002 .seealso: `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`
6003 @*/
6004 PetscErrorCode DMCopyDS(DM dm, DM newdm)
6005 {
6006   PetscInt Nds, s;
6007 
6008   PetscFunctionBegin;
6009   if (dm == newdm) PetscFunctionReturn(0);
6010   PetscCall(DMGetNumDS(dm, &Nds));
6011   PetscCall(DMClearDS(newdm));
6012   for (s = 0; s < Nds; ++s) {
6013     DMLabel  label;
6014     IS       fields;
6015     PetscDS  ds, newds;
6016     PetscInt Nbd, bd;
6017 
6018     PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds));
6019     /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */
6020     PetscCall(DMTransferDS_Internal(newdm, label, fields, ds));
6021     /* Commplete new labels in the new DS */
6022     PetscCall(DMGetRegionDS(newdm, label, NULL, &newds));
6023     PetscCall(PetscDSGetNumBoundary(newds, &Nbd));
6024     for (bd = 0; bd < Nbd; ++bd) {
6025       PetscWeakForm wf;
6026       DMLabel       label;
6027       PetscInt      field;
6028 
6029       PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL));
6030       PetscCall(PetscWeakFormReplaceLabel(wf, label));
6031     }
6032   }
6033   PetscCall(DMCompleteBCLabels_Internal(newdm));
6034   PetscFunctionReturn(0);
6035 }
6036 
6037 /*@
6038   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
6039 
6040   Collective on dm
6041 
6042   Input Parameter:
6043 . dm - The DM
6044 
6045   Output Parameter:
6046 . newdm - The DM
6047 
6048   Level: advanced
6049 
6050 .seealso: `DMCopyFields()`, `DMCopyDS()`
6051 @*/
6052 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
6053 {
6054   PetscFunctionBegin;
6055   PetscCall(DMCopyFields(dm, newdm));
6056   PetscCall(DMCopyDS(dm, newdm));
6057   PetscFunctionReturn(0);
6058 }
6059 
6060 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
6061 {
6062   DM dm_coord,dmc_coord;
6063   Vec coords,ccoords;
6064   Mat inject;
6065   PetscFunctionBegin;
6066   PetscCall(DMGetCoordinateDM(dm,&dm_coord));
6067   PetscCall(DMGetCoordinateDM(dmc,&dmc_coord));
6068   PetscCall(DMGetCoordinates(dm,&coords));
6069   PetscCall(DMGetCoordinates(dmc,&ccoords));
6070   if (coords && !ccoords) {
6071     PetscCall(DMCreateGlobalVector(dmc_coord,&ccoords));
6072     PetscCall(PetscObjectSetName((PetscObject)ccoords,"coordinates"));
6073     PetscCall(DMCreateInjection(dmc_coord,dm_coord,&inject));
6074     PetscCall(MatRestrict(inject,coords,ccoords));
6075     PetscCall(MatDestroy(&inject));
6076     PetscCall(DMSetCoordinates(dmc,ccoords));
6077     PetscCall(VecDestroy(&ccoords));
6078   }
6079   PetscFunctionReturn(0);
6080 }
6081 
6082 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
6083 {
6084   DM dm_coord,subdm_coord;
6085   Vec coords,ccoords,clcoords;
6086   VecScatter *scat_i,*scat_g;
6087   PetscFunctionBegin;
6088   PetscCall(DMGetCoordinateDM(dm,&dm_coord));
6089   PetscCall(DMGetCoordinateDM(subdm,&subdm_coord));
6090   PetscCall(DMGetCoordinates(dm,&coords));
6091   PetscCall(DMGetCoordinates(subdm,&ccoords));
6092   if (coords && !ccoords) {
6093     PetscCall(DMCreateGlobalVector(subdm_coord,&ccoords));
6094     PetscCall(PetscObjectSetName((PetscObject)ccoords,"coordinates"));
6095     PetscCall(DMCreateLocalVector(subdm_coord,&clcoords));
6096     PetscCall(PetscObjectSetName((PetscObject)clcoords,"coordinates"));
6097     PetscCall(DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g));
6098     PetscCall(VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD));
6099     PetscCall(VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD));
6100     PetscCall(VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD));
6101     PetscCall(VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD));
6102     PetscCall(DMSetCoordinates(subdm,ccoords));
6103     PetscCall(DMSetCoordinatesLocal(subdm,clcoords));
6104     PetscCall(VecScatterDestroy(&scat_i[0]));
6105     PetscCall(VecScatterDestroy(&scat_g[0]));
6106     PetscCall(VecDestroy(&ccoords));
6107     PetscCall(VecDestroy(&clcoords));
6108     PetscCall(PetscFree(scat_i));
6109     PetscCall(PetscFree(scat_g));
6110   }
6111   PetscFunctionReturn(0);
6112 }
6113 
6114 /*@
6115   DMGetDimension - Return the topological dimension of the DM
6116 
6117   Not collective
6118 
6119   Input Parameter:
6120 . dm - The DM
6121 
6122   Output Parameter:
6123 . dim - The topological dimension
6124 
6125   Level: beginner
6126 
6127 .seealso: `DMSetDimension()`, `DMCreate()`
6128 @*/
6129 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
6130 {
6131   PetscFunctionBegin;
6132   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6133   PetscValidIntPointer(dim, 2);
6134   *dim = dm->dim;
6135   PetscFunctionReturn(0);
6136 }
6137 
6138 /*@
6139   DMSetDimension - Set the topological dimension of the DM
6140 
6141   Collective on dm
6142 
6143   Input Parameters:
6144 + dm - The DM
6145 - dim - The topological dimension
6146 
6147   Level: beginner
6148 
6149 .seealso: `DMGetDimension()`, `DMCreate()`
6150 @*/
6151 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
6152 {
6153   PetscDS        ds;
6154   PetscInt       Nds, n;
6155 
6156   PetscFunctionBegin;
6157   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6158   PetscValidLogicalCollectiveInt(dm, dim, 2);
6159   dm->dim = dim;
6160   if (dm->dim >= 0) {
6161     PetscCall(DMGetNumDS(dm, &Nds));
6162     for (n = 0; n < Nds; ++n) {
6163       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds));
6164       if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6165     }
6166   }
6167   PetscFunctionReturn(0);
6168 }
6169 
6170 /*@
6171   DMGetDimPoints - Get the half-open interval for all points of a given dimension
6172 
6173   Collective on dm
6174 
6175   Input Parameters:
6176 + dm - the DM
6177 - dim - the dimension
6178 
6179   Output Parameters:
6180 + pStart - The first point of the given dimension
6181 - pEnd - The first point following points of the given dimension
6182 
6183   Note:
6184   The points are vertices in the Hasse diagram encoding the topology. This is explained in
6185   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
6186   then the interval is empty.
6187 
6188   Level: intermediate
6189 
6190 .seealso: `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()`
6191 @*/
6192 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
6193 {
6194   PetscInt       d;
6195 
6196   PetscFunctionBegin;
6197   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6198   PetscCall(DMGetDimension(dm, &d));
6199   PetscCheck((dim >= 0) && (dim <= d),PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim);
6200   PetscCheck(dm->ops->getdimpoints,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
6201   PetscCall((*dm->ops->getdimpoints)(dm, dim, pStart, pEnd));
6202   PetscFunctionReturn(0);
6203 }
6204 
6205 /*@
6206   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
6207 
6208   Collective on dm
6209 
6210   Input Parameters:
6211 + dm - the DM
6212 - c - coordinate vector
6213 
6214   Notes:
6215   The coordinates do include those for ghost points, which are in the local vector.
6216 
6217   The vector c should be destroyed by the caller.
6218 
6219   Level: intermediate
6220 
6221 .seealso: `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMDASetUniformCoordinates()`
6222 @*/
6223 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
6224 {
6225   PetscFunctionBegin;
6226   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6227   if (c) PetscValidHeaderSpecific(c,VEC_CLASSID,2);
6228   PetscCall(PetscObjectReference((PetscObject) c));
6229   PetscCall(VecDestroy(&dm->coordinates));
6230   dm->coordinates = c;
6231   PetscCall(VecDestroy(&dm->coordinatesLocal));
6232   PetscCall(DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL));
6233   PetscCall(DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL));
6234   PetscFunctionReturn(0);
6235 }
6236 
6237 /*@
6238   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
6239 
6240   Not collective
6241 
6242    Input Parameters:
6243 +  dm - the DM
6244 -  c - coordinate vector
6245 
6246   Notes:
6247   The coordinates of ghost points can be set using DMSetCoordinates()
6248   followed by DMGetCoordinatesLocal(). This is intended to enable the
6249   setting of ghost coordinates outside of the domain.
6250 
6251   The vector c should be destroyed by the caller.
6252 
6253   Level: intermediate
6254 
6255 .seealso: `DMGetCoordinatesLocal()`, `DMSetCoordinates()`, `DMGetCoordinates()`, `DMGetCoordinateDM()`
6256 @*/
6257 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
6258 {
6259   PetscFunctionBegin;
6260   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6261   if (c) PetscValidHeaderSpecific(c,VEC_CLASSID,2);
6262   PetscCall(PetscObjectReference((PetscObject) c));
6263   PetscCall(VecDestroy(&dm->coordinatesLocal));
6264 
6265   dm->coordinatesLocal = c;
6266 
6267   PetscCall(VecDestroy(&dm->coordinates));
6268   PetscFunctionReturn(0);
6269 }
6270 
6271 /*@
6272   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
6273 
6274   Collective on dm
6275 
6276   Input Parameter:
6277 . dm - the DM
6278 
6279   Output Parameter:
6280 . c - global coordinate vector
6281 
6282   Note:
6283   This is a borrowed reference, so the user should NOT destroy this vector. When the DM is
6284   destroyed the array will no longer be valid.
6285 
6286   Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates).
6287 
6288   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6289   and (x_0,y_0,z_0,x_1,y_1,z_1...)
6290 
6291   Level: intermediate
6292 
6293 .seealso: `DMSetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMDASetUniformCoordinates()`
6294 @*/
6295 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
6296 {
6297   PetscFunctionBegin;
6298   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6299   PetscValidPointer(c,2);
6300   if (!dm->coordinates && dm->coordinatesLocal) {
6301     DM        cdm = NULL;
6302     PetscBool localized;
6303 
6304     PetscCall(DMGetCoordinateDM(dm, &cdm));
6305     PetscCall(DMCreateGlobalVector(cdm, &dm->coordinates));
6306     PetscCall(DMGetCoordinatesLocalized(dm, &localized));
6307     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
6308     if (localized) {
6309       PetscInt cdim;
6310 
6311       PetscCall(DMGetCoordinateDim(dm, &cdim));
6312       PetscCall(VecSetBlockSize(dm->coordinates, cdim));
6313     }
6314     PetscCall(PetscObjectSetName((PetscObject) dm->coordinates, "coordinates"));
6315     PetscCall(DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates));
6316     PetscCall(DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates));
6317   }
6318   *c = dm->coordinates;
6319   PetscFunctionReturn(0);
6320 }
6321 
6322 /*@
6323   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
6324 
6325   Collective on dm
6326 
6327   Input Parameter:
6328 . dm - the DM
6329 
6330   Level: advanced
6331 
6332 .seealso: `DMGetCoordinatesLocalNoncollective()`
6333 @*/
6334 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6335 {
6336   PetscFunctionBegin;
6337   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6338   if (!dm->coordinatesLocal && dm->coordinates) {
6339     DM        cdm = NULL;
6340     PetscBool localized;
6341 
6342     PetscCall(DMGetCoordinateDM(dm, &cdm));
6343     PetscCall(DMCreateLocalVector(cdm, &dm->coordinatesLocal));
6344     PetscCall(DMGetCoordinatesLocalized(dm, &localized));
6345     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6346     if (localized) {
6347       PetscInt cdim;
6348 
6349       PetscCall(DMGetCoordinateDim(dm, &cdim));
6350       PetscCall(VecSetBlockSize(dm->coordinates, cdim));
6351     }
6352     PetscCall(PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates"));
6353     PetscCall(DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal));
6354     PetscCall(DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal));
6355   }
6356   PetscFunctionReturn(0);
6357 }
6358 
6359 /*@
6360   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
6361 
6362   Collective on dm
6363 
6364   Input Parameter:
6365 . dm - the DM
6366 
6367   Output Parameter:
6368 . c - coordinate vector
6369 
6370   Note:
6371   This is a borrowed reference, so the user should NOT destroy this vector
6372 
6373   Each process has the local and ghost coordinates
6374 
6375   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6376   and (x_0,y_0,z_0,x_1,y_1,z_1...)
6377 
6378   Level: intermediate
6379 
6380 .seealso: `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()`, `DMGetCoordinatesLocalNoncollective()`
6381 @*/
6382 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6383 {
6384   PetscFunctionBegin;
6385   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6386   PetscValidPointer(c,2);
6387   PetscCall(DMGetCoordinatesLocalSetUp(dm));
6388   *c = dm->coordinatesLocal;
6389   PetscFunctionReturn(0);
6390 }
6391 
6392 /*@
6393   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
6394 
6395   Not collective
6396 
6397   Input Parameter:
6398 . dm - the DM
6399 
6400   Output Parameter:
6401 . c - coordinate vector
6402 
6403   Level: advanced
6404 
6405 .seealso: `DMGetCoordinatesLocalSetUp()`, `DMGetCoordinatesLocal()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()`
6406 @*/
6407 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6408 {
6409   PetscFunctionBegin;
6410   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6411   PetscValidPointer(c,2);
6412   PetscCheck(dm->coordinatesLocal || !dm->coordinates,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6413   *c = dm->coordinatesLocal;
6414   PetscFunctionReturn(0);
6415 }
6416 
6417 /*@
6418   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
6419 
6420   Not collective
6421 
6422   Input Parameters:
6423 + dm - the DM
6424 - p - the IS of points whose coordinates will be returned
6425 
6426   Output Parameters:
6427 + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6428 - pCoord - the Vec with coordinates of points in p
6429 
6430   Note:
6431   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
6432 
6433   This creates a new vector, so the user SHOULD destroy this vector
6434 
6435   Each process has the local and ghost coordinates
6436 
6437   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6438   and (x_0,y_0,z_0,x_1,y_1,z_1...)
6439 
6440   Level: advanced
6441 
6442 .seealso: `DMSetCoordinatesLocal()`, `DMGetCoordinatesLocal()`, `DMGetCoordinatesLocalNoncollective()`, `DMGetCoordinatesLocalSetUp()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()`
6443 @*/
6444 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6445 {
6446   PetscSection        cs, newcs;
6447   Vec                 coords;
6448   const PetscScalar   *arr;
6449   PetscScalar         *newarr=NULL;
6450   PetscInt            n;
6451 
6452   PetscFunctionBegin;
6453   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6454   PetscValidHeaderSpecific(p, IS_CLASSID, 2);
6455   if (pCoordSection) PetscValidPointer(pCoordSection, 3);
6456   if (pCoord) PetscValidPointer(pCoord, 4);
6457   PetscCheck(dm->coordinatesLocal,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6458   PetscCheck(dm->coordinateDM && dm->coordinateDM->localSection,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6459   cs = dm->coordinateDM->localSection;
6460   coords = dm->coordinatesLocal;
6461   PetscCall(VecGetArrayRead(coords, &arr));
6462   PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL));
6463   PetscCall(VecRestoreArrayRead(coords, &arr));
6464   if (pCoord) {
6465     PetscCall(PetscSectionGetStorageSize(newcs, &n));
6466     /* set array in two steps to mimic PETSC_OWN_POINTER */
6467     PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord));
6468     PetscCall(VecReplaceArray(*pCoord, newarr));
6469   } else {
6470     PetscCall(PetscFree(newarr));
6471   }
6472   if (pCoordSection) {*pCoordSection = newcs;}
6473   else               PetscCall(PetscSectionDestroy(&newcs));
6474   PetscFunctionReturn(0);
6475 }
6476 
6477 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6478 {
6479   PetscFunctionBegin;
6480   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6481   PetscValidPointer(field,2);
6482   if (!dm->coordinateField) {
6483     if (dm->ops->createcoordinatefield) {
6484       PetscCall((*dm->ops->createcoordinatefield)(dm,&dm->coordinateField));
6485     }
6486   }
6487   *field = dm->coordinateField;
6488   PetscFunctionReturn(0);
6489 }
6490 
6491 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6492 {
6493   PetscFunctionBegin;
6494   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6495   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
6496   PetscCall(PetscObjectReference((PetscObject)field));
6497   PetscCall(DMFieldDestroy(&dm->coordinateField));
6498   dm->coordinateField = field;
6499   PetscFunctionReturn(0);
6500 }
6501 
6502 /*@
6503   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
6504 
6505   Collective on dm
6506 
6507   Input Parameter:
6508 . dm - the DM
6509 
6510   Output Parameter:
6511 . cdm - coordinate DM
6512 
6513   Level: intermediate
6514 
6515 .seealso: `DMSetCoordinateDM()`, `DMSetCoordinates()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`
6516 @*/
6517 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6518 {
6519   PetscFunctionBegin;
6520   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6521   PetscValidPointer(cdm,2);
6522   if (!dm->coordinateDM) {
6523     DM cdm;
6524 
6525     PetscCheck(dm->ops->createcoordinatedm,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6526     PetscCall((*dm->ops->createcoordinatedm)(dm, &cdm));
6527     PetscCall(PetscObjectSetName((PetscObject)cdm, "coordinateDM"));
6528     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6529      * until the call to CreateCoordinateDM) */
6530     PetscCall(DMDestroy(&dm->coordinateDM));
6531     dm->coordinateDM = cdm;
6532   }
6533   *cdm = dm->coordinateDM;
6534   PetscFunctionReturn(0);
6535 }
6536 
6537 /*@
6538   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
6539 
6540   Logically Collective on dm
6541 
6542   Input Parameters:
6543 + dm - the DM
6544 - cdm - coordinate DM
6545 
6546   Level: intermediate
6547 
6548 .seealso: `DMGetCoordinateDM()`, `DMSetCoordinates()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`
6549 @*/
6550 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6551 {
6552   PetscFunctionBegin;
6553   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6554   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
6555   PetscCall(PetscObjectReference((PetscObject)cdm));
6556   PetscCall(DMDestroy(&dm->coordinateDM));
6557   dm->coordinateDM = cdm;
6558   PetscFunctionReturn(0);
6559 }
6560 
6561 /*@
6562   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
6563 
6564   Not Collective
6565 
6566   Input Parameter:
6567 . dm - The DM object
6568 
6569   Output Parameter:
6570 . dim - The embedding dimension
6571 
6572   Level: intermediate
6573 
6574 .seealso: `DMSetCoordinateDim()`, `DMGetCoordinateSection()`, `DMGetCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()`
6575 @*/
6576 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6577 {
6578   PetscFunctionBegin;
6579   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6580   PetscValidIntPointer(dim, 2);
6581   if (dm->dimEmbed == PETSC_DEFAULT) {
6582     dm->dimEmbed = dm->dim;
6583   }
6584   *dim = dm->dimEmbed;
6585   PetscFunctionReturn(0);
6586 }
6587 
6588 /*@
6589   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
6590 
6591   Not Collective
6592 
6593   Input Parameters:
6594 + dm  - The DM object
6595 - dim - The embedding dimension
6596 
6597   Level: intermediate
6598 
6599 .seealso: `DMGetCoordinateDim()`, `DMSetCoordinateSection()`, `DMGetCoordinateSection()`, `DMGetLocalSection()`, `DMSetLocalSection()`
6600 @*/
6601 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6602 {
6603   PetscDS        ds;
6604   PetscInt       Nds, n;
6605 
6606   PetscFunctionBegin;
6607   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6608   dm->dimEmbed = dim;
6609   if (dm->dim >= 0) {
6610     PetscCall(DMGetNumDS(dm, &Nds));
6611     for (n = 0; n < Nds; ++n) {
6612       PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds));
6613       PetscCall(PetscDSSetCoordinateDimension(ds, dim));
6614     }
6615   }
6616   PetscFunctionReturn(0);
6617 }
6618 
6619 /*@
6620   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6621 
6622   Collective on dm
6623 
6624   Input Parameter:
6625 . dm - The DM object
6626 
6627   Output Parameter:
6628 . section - The PetscSection object
6629 
6630   Level: intermediate
6631 
6632 .seealso: `DMGetCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()`
6633 @*/
6634 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6635 {
6636   DM             cdm;
6637 
6638   PetscFunctionBegin;
6639   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6640   PetscValidPointer(section, 2);
6641   PetscCall(DMGetCoordinateDM(dm, &cdm));
6642   PetscCall(DMGetLocalSection(cdm, section));
6643   PetscFunctionReturn(0);
6644 }
6645 
6646 /*@
6647   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
6648 
6649   Not Collective
6650 
6651   Input Parameters:
6652 + dm      - The DM object
6653 . dim     - The embedding dimension, or PETSC_DETERMINE
6654 - section - The PetscSection object
6655 
6656   Level: intermediate
6657 
6658 .seealso: `DMGetCoordinateSection()`, `DMGetLocalSection()`, `DMSetLocalSection()`
6659 @*/
6660 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6661 {
6662   DM             cdm;
6663 
6664   PetscFunctionBegin;
6665   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6666   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
6667   PetscCall(DMGetCoordinateDM(dm, &cdm));
6668   PetscCall(DMSetLocalSection(cdm, section));
6669   if (dim == PETSC_DETERMINE) {
6670     PetscInt d = PETSC_DEFAULT;
6671     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
6672 
6673     PetscCall(PetscSectionGetChart(section, &pStart, &pEnd));
6674     PetscCall(DMGetDimPoints(dm, 0, &vStart, &vEnd));
6675     pStart = PetscMax(vStart, pStart);
6676     pEnd   = PetscMin(vEnd, pEnd);
6677     for (v = pStart; v < pEnd; ++v) {
6678       PetscCall(PetscSectionGetDof(section, v, &dd));
6679       if (dd) {d = dd; break;}
6680     }
6681     if (d >= 0) PetscCall(DMSetCoordinateDim(dm, d));
6682   }
6683   PetscFunctionReturn(0);
6684 }
6685 
6686 /*@
6687   DMProjectCoordinates - Project coordinates to a different space
6688 
6689   Input Parameters:
6690 + dm      - The DM object
6691 - disc    - The new coordinate discretization or NULL to ensure a coordinate discretization exists
6692 
6693   Level: intermediate
6694 
6695 .seealso: `DMGetCoordinateField()`
6696 @*/
6697 PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6698 {
6699   PetscFE        discOld;
6700   PetscClassId   classid;
6701   DM             cdmOld,cdmNew;
6702   Vec            coordsOld,coordsNew;
6703   Mat            matInterp;
6704   PetscBool      same_space = PETSC_TRUE;
6705 
6706   PetscFunctionBegin;
6707   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6708   if (disc) PetscValidHeaderSpecific(disc,PETSCFE_CLASSID,2);
6709 
6710   PetscCall(DMGetCoordinateDM(dm, &cdmOld));
6711   /* Check current discretization is compatible */
6712   PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld));
6713   PetscCall(PetscObjectGetClassId((PetscObject)discOld, &classid));
6714   if (classid != PETSCFE_CLASSID) {
6715     if (classid == PETSC_CONTAINER_CLASSID) {
6716       PetscFE        feLinear;
6717       DMPolytopeType ct;
6718       PetscInt       dim, dE, cStart, cEnd;
6719       PetscBool      simplex;
6720 
6721       /* Assume linear vertex coordinates */
6722       PetscCall(DMGetDimension(dm, &dim));
6723       PetscCall(DMGetCoordinateDim(dm, &dE));
6724       PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
6725       if (cEnd > cStart) {
6726         PetscCall(DMPlexGetCellType(dm, cStart, &ct));
6727         switch (ct) {
6728           case DM_POLYTOPE_TRI_PRISM:
6729           case DM_POLYTOPE_TRI_PRISM_TENSOR:
6730             SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6731           default: break;
6732         }
6733       }
6734       PetscCall(DMPlexIsSimplex(dm, &simplex));
6735       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear));
6736       PetscCall(DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear));
6737       PetscCall(PetscFEDestroy(&feLinear));
6738       PetscCall(DMCreateDS(cdmOld));
6739       PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject*)&discOld));
6740     } else {
6741       const char *discname;
6742 
6743       PetscCall(PetscObjectGetType((PetscObject)discOld, &discname));
6744       SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6745     }
6746   }
6747   if (!disc) PetscFunctionReturn(0);
6748   { // Check if the new space is the same as the old modulo quadrature
6749     PetscDualSpace dsOld, ds;
6750     PetscCall(PetscFEGetDualSpace(discOld, &dsOld));
6751     PetscCall(PetscFEGetDualSpace(disc, &ds));
6752     PetscCall(PetscDualSpaceEqual(dsOld, ds, &same_space));
6753   }
6754   /* Make a fresh clone of the coordinate DM */
6755   PetscCall(DMClone(cdmOld, &cdmNew));
6756   PetscCall(DMSetField(cdmNew, 0, NULL, (PetscObject) disc));
6757   PetscCall(DMCreateDS(cdmNew));
6758   PetscCall(DMGetCoordinates(dm, &coordsOld));
6759   if (same_space) {
6760     PetscCall(PetscObjectReference((PetscObject)coordsOld));
6761     coordsNew = coordsOld;
6762   } else { // Project the coordinate vector from old to new space
6763     PetscCall(DMCreateGlobalVector(cdmNew, &coordsNew));
6764     PetscCall(DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL));
6765     PetscCall(MatInterpolate(matInterp, coordsOld, coordsNew));
6766     PetscCall(MatDestroy(&matInterp));
6767   }
6768   /* Set new coordinate structures */
6769   PetscCall(DMSetCoordinateField(dm, NULL));
6770   PetscCall(DMSetCoordinateDM(dm, cdmNew));
6771   PetscCall(DMSetCoordinates(dm, coordsNew));
6772   PetscCall(VecDestroy(&coordsNew));
6773   PetscCall(DMDestroy(&cdmNew));
6774   PetscFunctionReturn(0);
6775 }
6776 
6777 /*@C
6778   DMGetPeriodicity - Get the description of mesh periodicity
6779 
6780   Input Parameter:
6781 . dm      - The DM object
6782 
6783   Output Parameters:
6784 + per     - Whether the DM is periodic or not
6785 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6786 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6787 - bd      - This describes the type of periodicity in each topological dimension
6788 
6789   Level: developer
6790 
6791 .seealso: `DMGetPeriodicity()`
6792 @*/
6793 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6794 {
6795   PetscFunctionBegin;
6796   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6797   if (per)     *per     = dm->periodic;
6798   if (L)       *L       = dm->L;
6799   if (maxCell) *maxCell = dm->maxCell;
6800   if (bd)      *bd      = dm->bdtype;
6801   PetscFunctionReturn(0);
6802 }
6803 
6804 /*@C
6805   DMSetPeriodicity - Set the description of mesh periodicity
6806 
6807   Input Parameters:
6808 + dm      - The DM object
6809 . per     - Whether the DM is periodic or not.
6810 . 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.
6811 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6812 - bd      - This describes the type of periodicity in each topological dimension
6813 
6814   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.
6815 
6816   Level: developer
6817 
6818 .seealso: `DMGetPeriodicity()`
6819 @*/
6820 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6821 {
6822   PetscInt       dim, d;
6823 
6824   PetscFunctionBegin;
6825   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6826   PetscValidLogicalCollectiveBool(dm,per,2);
6827   if (maxCell) {PetscValidRealPointer(maxCell,3);}
6828   if (L)       {PetscValidRealPointer(L,4);}
6829   if (bd)      {PetscValidPointer(bd,5);}
6830   PetscCall(DMGetDimension(dm, &dim));
6831   if (maxCell) {
6832     if (!dm->maxCell) PetscCall(PetscMalloc1(dim, &dm->maxCell));
6833     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6834   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6835     PetscCall(PetscFree(dm->maxCell));
6836   }
6837 
6838   if (L) {
6839     if (!dm->L) PetscCall(PetscMalloc1(dim, &dm->L));
6840     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6841   }
6842   if (bd) {
6843     if (!dm->bdtype) PetscCall(PetscMalloc1(dim, &dm->bdtype));
6844     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6845   }
6846   dm->periodic = per;
6847   PetscFunctionReturn(0);
6848 }
6849 
6850 /*@
6851   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.
6852 
6853   Input Parameters:
6854 + dm     - The DM
6855 . in     - The input coordinate point (dim numbers)
6856 - endpoint - Include the endpoint L_i
6857 
6858   Output Parameter:
6859 . out - The localized coordinate point
6860 
6861   Level: developer
6862 
6863 .seealso: `DMLocalizeCoordinates()`, `DMLocalizeAddCoordinate()`
6864 @*/
6865 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6866 {
6867   PetscInt       dim, d;
6868 
6869   PetscFunctionBegin;
6870   PetscCall(DMGetCoordinateDim(dm, &dim));
6871   if (!dm->maxCell) {
6872     for (d = 0; d < dim; ++d) out[d] = in[d];
6873   } else {
6874     if (endpoint) {
6875       for (d = 0; d < dim; ++d) {
6876         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)) {
6877           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6878         } else {
6879           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6880         }
6881       }
6882     } else {
6883       for (d = 0; d < dim; ++d) {
6884         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6885       }
6886     }
6887   }
6888   PetscFunctionReturn(0);
6889 }
6890 
6891 /*
6892   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.
6893 
6894   Input Parameters:
6895 + dm     - The DM
6896 . dim    - The spatial dimension
6897 . anchor - The anchor point, the input point can be no more than maxCell away from it
6898 - in     - The input coordinate point (dim numbers)
6899 
6900   Output Parameter:
6901 . out - The localized coordinate point
6902 
6903   Level: developer
6904 
6905   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
6906 
6907 .seealso: `DMLocalizeCoordinates()`, `DMLocalizeAddCoordinate()`
6908 */
6909 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6910 {
6911   PetscInt d;
6912 
6913   PetscFunctionBegin;
6914   if (!dm->maxCell) {
6915     for (d = 0; d < dim; ++d) out[d] = in[d];
6916   } else {
6917     for (d = 0; d < dim; ++d) {
6918       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6919         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6920       } else {
6921         out[d] = in[d];
6922       }
6923     }
6924   }
6925   PetscFunctionReturn(0);
6926 }
6927 
6928 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6929 {
6930   PetscInt d;
6931 
6932   PetscFunctionBegin;
6933   if (!dm->maxCell) {
6934     for (d = 0; d < dim; ++d) out[d] = in[d];
6935   } else {
6936     for (d = 0; d < dim; ++d) {
6937       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6938         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6939       } else {
6940         out[d] = in[d];
6941       }
6942     }
6943   }
6944   PetscFunctionReturn(0);
6945 }
6946 
6947 /*
6948   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.
6949 
6950   Input Parameters:
6951 + dm     - The DM
6952 . dim    - The spatial dimension
6953 . anchor - The anchor point, the input point can be no more than maxCell away from it
6954 . in     - The input coordinate delta (dim numbers)
6955 - out    - The input coordinate point (dim numbers)
6956 
6957   Output Parameter:
6958 . out    - The localized coordinate in + out
6959 
6960   Level: developer
6961 
6962   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
6963 
6964 .seealso: `DMLocalizeCoordinates()`, `DMLocalizeCoordinate()`
6965 */
6966 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6967 {
6968   PetscInt d;
6969 
6970   PetscFunctionBegin;
6971   if (!dm->maxCell) {
6972     for (d = 0; d < dim; ++d) out[d] += in[d];
6973   } else {
6974     for (d = 0; d < dim; ++d) {
6975       const PetscReal maxC = dm->maxCell[d];
6976 
6977       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6978         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6979 
6980         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6981           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]));
6982         out[d] += newCoord;
6983       } else {
6984         out[d] += in[d];
6985       }
6986     }
6987   }
6988   PetscFunctionReturn(0);
6989 }
6990 
6991 /*@
6992   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6993 
6994   Not collective
6995 
6996   Input Parameter:
6997 . dm - The DM
6998 
6999   Output Parameter:
7000   areLocalized - True if localized
7001 
7002   Level: developer
7003 
7004 .seealso: `DMLocalizeCoordinates()`, `DMGetCoordinatesLocalized()`, `DMSetPeriodicity()`
7005 @*/
7006 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
7007 {
7008   DM             cdm;
7009   PetscSection   coordSection;
7010   PetscInt       depth, cStart, cEnd, sStart, sEnd, c, dof;
7011   PetscBool      isPlex, alreadyLocalized;
7012 
7013   PetscFunctionBegin;
7014   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7015   PetscValidBoolPointer(areLocalized, 2);
7016   *areLocalized = PETSC_FALSE;
7017 
7018   /* We need some generic way of refering to cells/vertices */
7019   PetscCall(DMGetCoordinateDM(dm, &cdm));
7020   PetscCall(PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex));
7021   if (!isPlex) PetscFunctionReturn(0);
7022   PetscCall(DMPlexGetDepth(cdm, &depth));
7023   if (!depth) PetscFunctionReturn(0);
7024 
7025   PetscCall(DMGetCoordinateSection(dm, &coordSection));
7026   PetscCall(DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd));
7027   PetscCall(PetscSectionGetChart(coordSection, &sStart, &sEnd));
7028   alreadyLocalized = PETSC_FALSE;
7029   for (c = cStart; c < cEnd; ++c) {
7030     if (c < sStart || c >= sEnd) continue;
7031     PetscCall(PetscSectionGetDof(coordSection, c, &dof));
7032     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
7033   }
7034   *areLocalized = alreadyLocalized;
7035   PetscFunctionReturn(0);
7036 }
7037 
7038 /*@
7039   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
7040 
7041   Collective on dm
7042 
7043   Input Parameter:
7044 . dm - The DM
7045 
7046   Output Parameter:
7047   areLocalized - True if localized
7048 
7049   Level: developer
7050 
7051 .seealso: `DMLocalizeCoordinates()`, `DMSetPeriodicity()`, `DMGetCoordinatesLocalizedLocal()`
7052 @*/
7053 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
7054 {
7055   PetscBool      localized;
7056 
7057   PetscFunctionBegin;
7058   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7059   PetscValidBoolPointer(areLocalized, 2);
7060   PetscCall(DMGetCoordinatesLocalizedLocal(dm,&localized));
7061   PetscCall(MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm)));
7062   PetscFunctionReturn(0);
7063 }
7064 
7065 /*@
7066   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
7067 
7068   Collective on dm
7069 
7070   Input Parameter:
7071 . dm - The DM
7072 
7073   Level: developer
7074 
7075 .seealso: `DMSetPeriodicity()`, `DMLocalizeCoordinate()`, `DMLocalizeAddCoordinate()`
7076 @*/
7077 PetscErrorCode DMLocalizeCoordinates(DM dm)
7078 {
7079   DM             cdm;
7080   PetscSection   coordSection, cSection;
7081   Vec            coordinates,  cVec;
7082   PetscScalar   *coords, *coords2, *anchor, *localized;
7083   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
7084   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
7085   PetscInt       maxHeight = 0, h;
7086   PetscInt       *pStart = NULL, *pEnd = NULL;
7087 
7088   PetscFunctionBegin;
7089   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7090   if (!dm->periodic) PetscFunctionReturn(0);
7091   PetscCall(DMGetCoordinatesLocalized(dm, &alreadyLocalized));
7092   if (alreadyLocalized) PetscFunctionReturn(0);
7093 
7094   /* We need some generic way of refering to cells/vertices */
7095   PetscCall(DMGetCoordinateDM(dm, &cdm));
7096   {
7097     PetscBool isplex;
7098 
7099     PetscCall(PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex));
7100     if (isplex) {
7101       PetscCall(DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd));
7102       PetscCall(DMPlexGetMaxProjectionHeight(cdm,&maxHeight));
7103       PetscCall(DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart));
7104       pEnd = &pStart[maxHeight + 1];
7105       newStart = vStart;
7106       newEnd   = vEnd;
7107       for (h = 0; h <= maxHeight; h++) {
7108         PetscCall(DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]));
7109         newStart = PetscMin(newStart,pStart[h]);
7110         newEnd   = PetscMax(newEnd,pEnd[h]);
7111       }
7112     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
7113   }
7114   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
7115   PetscCheck(coordinates,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
7116   PetscCall(DMGetCoordinateSection(dm, &coordSection));
7117   PetscCall(VecGetBlockSize(coordinates, &bs));
7118   PetscCall(PetscSectionGetChart(coordSection,&sStart,&sEnd));
7119 
7120   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection));
7121   PetscCall(PetscSectionSetNumFields(cSection, 1));
7122   PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &Nc));
7123   PetscCall(PetscSectionSetFieldComponents(cSection, 0, Nc));
7124   PetscCall(PetscSectionSetChart(cSection, newStart, newEnd));
7125 
7126   PetscCall(DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor));
7127   localized = &anchor[bs];
7128   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
7129   for (h = 0; h <= maxHeight; h++) {
7130     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
7131 
7132     for (c = cStart; c < cEnd; ++c) {
7133       PetscScalar *cellCoords = NULL;
7134       PetscInt     b;
7135 
7136       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
7137       PetscCall(DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords));
7138       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7139       for (d = 0; d < dof/bs; ++d) {
7140         PetscCall(DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized));
7141         for (b = 0; b < bs; b++) {
7142           if (cellCoords[d*bs + b] != localized[b]) break;
7143         }
7144         if (b < bs) break;
7145       }
7146       if (d < dof/bs) {
7147         if (c >= sStart && c < sEnd) {
7148           PetscInt cdof;
7149 
7150           PetscCall(PetscSectionGetDof(coordSection, c, &cdof));
7151           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
7152         }
7153         PetscCall(PetscSectionSetDof(cSection, c, dof));
7154         PetscCall(PetscSectionSetFieldDof(cSection, c, 0, dof));
7155       }
7156       PetscCall(DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords));
7157     }
7158   }
7159   PetscCallMPI(MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm)));
7160   if (alreadyLocalizedGlobal) {
7161     PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor));
7162     PetscCall(PetscSectionDestroy(&cSection));
7163     PetscCall(DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart));
7164     PetscFunctionReturn(0);
7165   }
7166   for (v = vStart; v < vEnd; ++v) {
7167     PetscCall(PetscSectionGetDof(coordSection, v, &dof));
7168     PetscCall(PetscSectionSetDof(cSection, v, dof));
7169     PetscCall(PetscSectionSetFieldDof(cSection, v, 0, dof));
7170   }
7171   PetscCall(PetscSectionSetUp(cSection));
7172   PetscCall(PetscSectionGetStorageSize(cSection, &coordSize));
7173   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
7174   PetscCall(PetscObjectSetName((PetscObject)cVec,"coordinates"));
7175   PetscCall(VecSetBlockSize(cVec, bs));
7176   PetscCall(VecSetSizes(cVec, coordSize, PETSC_DETERMINE));
7177   PetscCall(VecSetType(cVec, VECSTANDARD));
7178   PetscCall(VecGetArrayRead(coordinates, (const PetscScalar**)&coords));
7179   PetscCall(VecGetArray(cVec, &coords2));
7180   for (v = vStart; v < vEnd; ++v) {
7181     PetscCall(PetscSectionGetDof(coordSection, v, &dof));
7182     PetscCall(PetscSectionGetOffset(coordSection, v, &off));
7183     PetscCall(PetscSectionGetOffset(cSection,     v, &off2));
7184     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
7185   }
7186   for (h = 0; h <= maxHeight; h++) {
7187     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
7188 
7189     for (c = cStart; c < cEnd; ++c) {
7190       PetscScalar *cellCoords = NULL;
7191       PetscInt     b, cdof;
7192 
7193       PetscCall(PetscSectionGetDof(cSection,c,&cdof));
7194       if (!cdof) continue;
7195       PetscCall(DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords));
7196       PetscCall(PetscSectionGetOffset(cSection, c, &off2));
7197       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
7198       for (d = 0; d < dof/bs; ++d) PetscCall(DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]));
7199       PetscCall(DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords));
7200     }
7201   }
7202   PetscCall(DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor));
7203   PetscCall(DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart));
7204   PetscCall(VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords));
7205   PetscCall(VecRestoreArray(cVec, &coords2));
7206   PetscCall(DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection));
7207   PetscCall(DMSetCoordinatesLocal(dm, cVec));
7208   PetscCall(VecDestroy(&cVec));
7209   PetscCall(PetscSectionDestroy(&cSection));
7210   PetscFunctionReturn(0);
7211 }
7212 
7213 /*@
7214   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
7215 
7216   Collective on v (see explanation below)
7217 
7218   Input Parameters:
7219 + dm - The DM
7220 - ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
7221 
7222   Input/Output Parameters:
7223 + v - The Vec of points, on output contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
7224 - cellSF - Points to either NULL, or a PetscSF with guesses for which cells contain each point;
7225            on output, the PetscSF containing the ranks and local indices of the containing points
7226 
7227   Level: developer
7228 
7229   Notes:
7230   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
7231   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
7232 
7233   If *cellSF is NULL on input, a PetscSF will be created.
7234   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
7235 
7236   An array that maps each point to its containing cell can be obtained with
7237 
7238 $    const PetscSFNode *cells;
7239 $    PetscInt           nFound;
7240 $    const PetscInt    *found;
7241 $
7242 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
7243 
7244   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
7245   the index of the cell in its rank's local numbering.
7246 
7247 .seealso: `DMSetCoordinates()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMPointLocationType`
7248 @*/
7249 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
7250 {
7251   PetscFunctionBegin;
7252   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7253   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
7254   PetscValidPointer(cellSF,4);
7255   if (*cellSF) {
7256     PetscMPIInt result;
7257 
7258     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
7259     PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result));
7260     PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
7261   } else {
7262     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF));
7263   }
7264   PetscCheck(dm->ops->locatepoints,PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
7265   PetscCall(PetscLogEventBegin(DM_LocatePoints,dm,0,0,0));
7266   PetscCall((*dm->ops->locatepoints)(dm,v,ltype,*cellSF));
7267   PetscCall(PetscLogEventEnd(DM_LocatePoints,dm,0,0,0));
7268   PetscFunctionReturn(0);
7269 }
7270 
7271 /*@
7272   DMGetOutputDM - Retrieve the DM associated with the layout for output
7273 
7274   Collective on dm
7275 
7276   Input Parameter:
7277 . dm - The original DM
7278 
7279   Output Parameter:
7280 . odm - The DM which provides the layout for output
7281 
7282   Level: intermediate
7283 
7284 .seealso: `VecView()`, `DMGetGlobalSection()`
7285 @*/
7286 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
7287 {
7288   PetscSection   section;
7289   PetscBool      hasConstraints, ghasConstraints;
7290 
7291   PetscFunctionBegin;
7292   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7293   PetscValidPointer(odm,2);
7294   PetscCall(DMGetLocalSection(dm, &section));
7295   PetscCall(PetscSectionHasConstraints(section, &hasConstraints));
7296   PetscCallMPI(MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm)));
7297   if (!ghasConstraints) {
7298     *odm = dm;
7299     PetscFunctionReturn(0);
7300   }
7301   if (!dm->dmBC) {
7302     PetscSection newSection, gsection;
7303     PetscSF      sf;
7304 
7305     PetscCall(DMClone(dm, &dm->dmBC));
7306     PetscCall(DMCopyDisc(dm, dm->dmBC));
7307     PetscCall(PetscSectionClone(section, &newSection));
7308     PetscCall(DMSetLocalSection(dm->dmBC, newSection));
7309     PetscCall(PetscSectionDestroy(&newSection));
7310     PetscCall(DMGetPointSF(dm->dmBC, &sf));
7311     PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection));
7312     PetscCall(DMSetGlobalSection(dm->dmBC, gsection));
7313     PetscCall(PetscSectionDestroy(&gsection));
7314   }
7315   *odm = dm->dmBC;
7316   PetscFunctionReturn(0);
7317 }
7318 
7319 /*@
7320   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
7321 
7322   Input Parameter:
7323 . dm - The original DM
7324 
7325   Output Parameters:
7326 + num - The output sequence number
7327 - val - The output sequence value
7328 
7329   Level: intermediate
7330 
7331   Note: This is intended for output that should appear in sequence, for instance
7332   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7333 
7334 .seealso: `VecView()`
7335 @*/
7336 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7337 {
7338   PetscFunctionBegin;
7339   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7340   if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;}
7341   if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;}
7342   PetscFunctionReturn(0);
7343 }
7344 
7345 /*@
7346   DMSetOutputSequenceNumber - Set the sequence number/value for output
7347 
7348   Input Parameters:
7349 + dm - The original DM
7350 . num - The output sequence number
7351 - val - The output sequence value
7352 
7353   Level: intermediate
7354 
7355   Note: This is intended for output that should appear in sequence, for instance
7356   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7357 
7358 .seealso: `VecView()`
7359 @*/
7360 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7361 {
7362   PetscFunctionBegin;
7363   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7364   dm->outputSequenceNum = num;
7365   dm->outputSequenceVal = val;
7366   PetscFunctionReturn(0);
7367 }
7368 
7369 /*@C
7370   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7371 
7372   Input Parameters:
7373 + dm   - The original DM
7374 . name - The sequence name
7375 - num  - The output sequence number
7376 
7377   Output Parameter:
7378 . val  - The output sequence value
7379 
7380   Level: intermediate
7381 
7382   Note: This is intended for output that should appear in sequence, for instance
7383   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7384 
7385 .seealso: `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()`
7386 @*/
7387 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7388 {
7389   PetscBool      ishdf5;
7390 
7391   PetscFunctionBegin;
7392   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7393   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
7394   PetscValidRealPointer(val,5);
7395   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5));
7396   if (ishdf5) {
7397 #if defined(PETSC_HAVE_HDF5)
7398     PetscScalar value;
7399 
7400     PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer));
7401     *val = PetscRealPart(value);
7402 #endif
7403   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7404   PetscFunctionReturn(0);
7405 }
7406 
7407 /*@
7408   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7409 
7410   Not collective
7411 
7412   Input Parameter:
7413 . dm - The DM
7414 
7415   Output Parameter:
7416 . useNatural - The flag to build the mapping to a natural order during distribution
7417 
7418   Level: beginner
7419 
7420 .seealso: `DMSetUseNatural()`, `DMCreate()`
7421 @*/
7422 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7423 {
7424   PetscFunctionBegin;
7425   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7426   PetscValidBoolPointer(useNatural, 2);
7427   *useNatural = dm->useNatural;
7428   PetscFunctionReturn(0);
7429 }
7430 
7431 /*@
7432   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7433 
7434   Collective on dm
7435 
7436   Input Parameters:
7437 + dm - The DM
7438 - useNatural - The flag to build the mapping to a natural order during distribution
7439 
7440   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7441 
7442   Level: beginner
7443 
7444 .seealso: `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()`
7445 @*/
7446 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7447 {
7448   PetscFunctionBegin;
7449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7450   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
7451   dm->useNatural = useNatural;
7452   PetscFunctionReturn(0);
7453 }
7454 
7455 /*@C
7456   DMCreateLabel - Create a label of the given name if it does not already exist
7457 
7458   Not Collective
7459 
7460   Input Parameters:
7461 + dm   - The DM object
7462 - name - The label name
7463 
7464   Level: intermediate
7465 
7466 .seealso: `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7467 @*/
7468 PetscErrorCode DMCreateLabel(DM dm, const char name[])
7469 {
7470   PetscBool      flg;
7471   DMLabel        label;
7472 
7473   PetscFunctionBegin;
7474   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7475   PetscValidCharPointer(name, 2);
7476   PetscCall(DMHasLabel(dm, name, &flg));
7477   if (!flg) {
7478     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
7479     PetscCall(DMAddLabel(dm, label));
7480     PetscCall(DMLabelDestroy(&label));
7481   }
7482   PetscFunctionReturn(0);
7483 }
7484 
7485 /*@C
7486   DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists, move it to this index.
7487 
7488   Not Collective
7489 
7490   Input Parameters:
7491 + dm   - The DM object
7492 . l    - The index for the label
7493 - name - The label name
7494 
7495   Level: intermediate
7496 
7497 .seealso: `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7498 @*/
7499 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7500 {
7501   DMLabelLink    orig, prev = NULL;
7502   DMLabel        label;
7503   PetscInt       Nl, m;
7504   PetscBool      flg, match;
7505   const char    *lname;
7506 
7507   PetscFunctionBegin;
7508   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7509   PetscValidCharPointer(name, 3);
7510   PetscCall(DMHasLabel(dm, name, &flg));
7511   if (!flg) {
7512     PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label));
7513     PetscCall(DMAddLabel(dm, label));
7514     PetscCall(DMLabelDestroy(&label));
7515   }
7516   PetscCall(DMGetNumLabels(dm, &Nl));
7517   PetscCheck(l < Nl,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl);
7518   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7519     PetscCall(PetscObjectGetName((PetscObject) orig->label, &lname));
7520     PetscCall(PetscStrcmp(name, lname, &match));
7521     if (match) break;
7522   }
7523   if (m == l) PetscFunctionReturn(0);
7524   if (!m) dm->labels = orig->next;
7525   else    prev->next = orig->next;
7526   if (!l) {
7527     orig->next = dm->labels;
7528     dm->labels = orig;
7529   } else {
7530     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7531     orig->next = prev->next;
7532     prev->next = orig;
7533   }
7534   PetscFunctionReturn(0);
7535 }
7536 
7537 /*@C
7538   DMGetLabelValue - Get the value in a DMLabel for the given point, with -1 as the default
7539 
7540   Not Collective
7541 
7542   Input Parameters:
7543 + dm   - The DM object
7544 . name - The label name
7545 - point - The mesh point
7546 
7547   Output Parameter:
7548 . value - The label value for this point, or -1 if the point is not in the label
7549 
7550   Level: beginner
7551 
7552 .seealso: `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7553 @*/
7554 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7555 {
7556   DMLabel        label;
7557 
7558   PetscFunctionBegin;
7559   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7560   PetscValidCharPointer(name, 2);
7561   PetscCall(DMGetLabel(dm, name, &label));
7562   PetscCheck(label,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7563   PetscCall(DMLabelGetValue(label, point, value));
7564   PetscFunctionReturn(0);
7565 }
7566 
7567 /*@C
7568   DMSetLabelValue - Add a point to a DMLabel with given value
7569 
7570   Not Collective
7571 
7572   Input Parameters:
7573 + dm   - The DM object
7574 . name - The label name
7575 . point - The mesh point
7576 - value - The label value for this point
7577 
7578   Output Parameter:
7579 
7580   Level: beginner
7581 
7582 .seealso: `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7583 @*/
7584 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7585 {
7586   DMLabel        label;
7587 
7588   PetscFunctionBegin;
7589   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7590   PetscValidCharPointer(name, 2);
7591   PetscCall(DMGetLabel(dm, name, &label));
7592   if (!label) {
7593     PetscCall(DMCreateLabel(dm, name));
7594     PetscCall(DMGetLabel(dm, name, &label));
7595   }
7596   PetscCall(DMLabelSetValue(label, point, value));
7597   PetscFunctionReturn(0);
7598 }
7599 
7600 /*@C
7601   DMClearLabelValue - Remove a point from a DMLabel with given value
7602 
7603   Not Collective
7604 
7605   Input Parameters:
7606 + dm   - The DM object
7607 . name - The label name
7608 . point - The mesh point
7609 - value - The label value for this point
7610 
7611   Output Parameter:
7612 
7613   Level: beginner
7614 
7615 .seealso: `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7616 @*/
7617 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7618 {
7619   DMLabel        label;
7620 
7621   PetscFunctionBegin;
7622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7623   PetscValidCharPointer(name, 2);
7624   PetscCall(DMGetLabel(dm, name, &label));
7625   if (!label) PetscFunctionReturn(0);
7626   PetscCall(DMLabelClearValue(label, point, value));
7627   PetscFunctionReturn(0);
7628 }
7629 
7630 /*@C
7631   DMGetLabelSize - Get the number of different integer ids in a Label
7632 
7633   Not Collective
7634 
7635   Input Parameters:
7636 + dm   - The DM object
7637 - name - The label name
7638 
7639   Output Parameter:
7640 . size - The number of different integer ids, or 0 if the label does not exist
7641 
7642   Level: beginner
7643 
7644 .seealso: `DMLabelGetNumValues()`, `DMSetLabelValue()`
7645 @*/
7646 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7647 {
7648   DMLabel        label;
7649 
7650   PetscFunctionBegin;
7651   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7652   PetscValidCharPointer(name, 2);
7653   PetscValidIntPointer(size, 3);
7654   PetscCall(DMGetLabel(dm, name, &label));
7655   *size = 0;
7656   if (!label) PetscFunctionReturn(0);
7657   PetscCall(DMLabelGetNumValues(label, size));
7658   PetscFunctionReturn(0);
7659 }
7660 
7661 /*@C
7662   DMGetLabelIdIS - Get the integer ids in a label
7663 
7664   Not Collective
7665 
7666   Input Parameters:
7667 + mesh - The DM object
7668 - name - The label name
7669 
7670   Output Parameter:
7671 . ids - The integer ids, or NULL if the label does not exist
7672 
7673   Level: beginner
7674 
7675 .seealso: `DMLabelGetValueIS()`, `DMGetLabelSize()`
7676 @*/
7677 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7678 {
7679   DMLabel        label;
7680 
7681   PetscFunctionBegin;
7682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7683   PetscValidCharPointer(name, 2);
7684   PetscValidPointer(ids, 3);
7685   PetscCall(DMGetLabel(dm, name, &label));
7686   *ids = NULL;
7687   if (label) {
7688     PetscCall(DMLabelGetValueIS(label, ids));
7689   } else {
7690     /* returning an empty IS */
7691     PetscCall(ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids));
7692   }
7693   PetscFunctionReturn(0);
7694 }
7695 
7696 /*@C
7697   DMGetStratumSize - Get the number of points in a label stratum
7698 
7699   Not Collective
7700 
7701   Input Parameters:
7702 + dm - The DM object
7703 . name - The label name
7704 - value - The stratum value
7705 
7706   Output Parameter:
7707 . size - The stratum size
7708 
7709   Level: beginner
7710 
7711 .seealso: `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()`
7712 @*/
7713 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7714 {
7715   DMLabel        label;
7716 
7717   PetscFunctionBegin;
7718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7719   PetscValidCharPointer(name, 2);
7720   PetscValidIntPointer(size, 4);
7721   PetscCall(DMGetLabel(dm, name, &label));
7722   *size = 0;
7723   if (!label) PetscFunctionReturn(0);
7724   PetscCall(DMLabelGetStratumSize(label, value, size));
7725   PetscFunctionReturn(0);
7726 }
7727 
7728 /*@C
7729   DMGetStratumIS - Get the points in a label stratum
7730 
7731   Not Collective
7732 
7733   Input Parameters:
7734 + dm - The DM object
7735 . name - The label name
7736 - value - The stratum value
7737 
7738   Output Parameter:
7739 . points - The stratum points, or NULL if the label does not exist or does not have that value
7740 
7741   Level: beginner
7742 
7743 .seealso: `DMLabelGetStratumIS()`, `DMGetStratumSize()`
7744 @*/
7745 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7746 {
7747   DMLabel        label;
7748 
7749   PetscFunctionBegin;
7750   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7751   PetscValidCharPointer(name, 2);
7752   PetscValidPointer(points, 4);
7753   PetscCall(DMGetLabel(dm, name, &label));
7754   *points = NULL;
7755   if (!label) PetscFunctionReturn(0);
7756   PetscCall(DMLabelGetStratumIS(label, value, points));
7757   PetscFunctionReturn(0);
7758 }
7759 
7760 /*@C
7761   DMSetStratumIS - Set the points in a label stratum
7762 
7763   Not Collective
7764 
7765   Input Parameters:
7766 + dm - The DM object
7767 . name - The label name
7768 . value - The stratum value
7769 - points - The stratum points
7770 
7771   Level: beginner
7772 
7773 .seealso: `DMLabelSetStratumIS()`, `DMGetStratumSize()`
7774 @*/
7775 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7776 {
7777   DMLabel        label;
7778 
7779   PetscFunctionBegin;
7780   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7781   PetscValidCharPointer(name, 2);
7782   PetscValidPointer(points, 4);
7783   PetscCall(DMGetLabel(dm, name, &label));
7784   if (!label) PetscFunctionReturn(0);
7785   PetscCall(DMLabelSetStratumIS(label, value, points));
7786   PetscFunctionReturn(0);
7787 }
7788 
7789 /*@C
7790   DMClearLabelStratum - Remove all points from a stratum from a DMLabel
7791 
7792   Not Collective
7793 
7794   Input Parameters:
7795 + dm   - The DM object
7796 . name - The label name
7797 - value - The label value for this point
7798 
7799   Output Parameter:
7800 
7801   Level: beginner
7802 
7803 .seealso: `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()`
7804 @*/
7805 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7806 {
7807   DMLabel        label;
7808 
7809   PetscFunctionBegin;
7810   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7811   PetscValidCharPointer(name, 2);
7812   PetscCall(DMGetLabel(dm, name, &label));
7813   if (!label) PetscFunctionReturn(0);
7814   PetscCall(DMLabelClearStratum(label, value));
7815   PetscFunctionReturn(0);
7816 }
7817 
7818 /*@
7819   DMGetNumLabels - Return the number of labels defined by the mesh
7820 
7821   Not Collective
7822 
7823   Input Parameter:
7824 . dm   - The DM object
7825 
7826   Output Parameter:
7827 . numLabels - the number of Labels
7828 
7829   Level: intermediate
7830 
7831 .seealso: `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7832 @*/
7833 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7834 {
7835   DMLabelLink next = dm->labels;
7836   PetscInt  n    = 0;
7837 
7838   PetscFunctionBegin;
7839   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7840   PetscValidIntPointer(numLabels, 2);
7841   while (next) {++n; next = next->next;}
7842   *numLabels = n;
7843   PetscFunctionReturn(0);
7844 }
7845 
7846 /*@C
7847   DMGetLabelName - Return the name of nth label
7848 
7849   Not Collective
7850 
7851   Input Parameters:
7852 + dm - The DM object
7853 - n  - the label number
7854 
7855   Output Parameter:
7856 . name - the label name
7857 
7858   Level: intermediate
7859 
7860 .seealso: `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7861 @*/
7862 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7863 {
7864   DMLabelLink    next = dm->labels;
7865   PetscInt       l    = 0;
7866 
7867   PetscFunctionBegin;
7868   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7869   PetscValidPointer(name, 3);
7870   while (next) {
7871     if (l == n) {
7872       PetscCall(PetscObjectGetName((PetscObject) next->label, name));
7873       PetscFunctionReturn(0);
7874     }
7875     ++l;
7876     next = next->next;
7877   }
7878   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7879 }
7880 
7881 /*@C
7882   DMHasLabel - Determine whether the mesh has a label of a given name
7883 
7884   Not Collective
7885 
7886   Input Parameters:
7887 + dm   - The DM object
7888 - name - The label name
7889 
7890   Output Parameter:
7891 . hasLabel - PETSC_TRUE if the label is present
7892 
7893   Level: intermediate
7894 
7895 .seealso: `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7896 @*/
7897 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7898 {
7899   DMLabelLink    next = dm->labels;
7900   const char    *lname;
7901 
7902   PetscFunctionBegin;
7903   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7904   PetscValidCharPointer(name, 2);
7905   PetscValidBoolPointer(hasLabel, 3);
7906   *hasLabel = PETSC_FALSE;
7907   while (next) {
7908     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
7909     PetscCall(PetscStrcmp(name, lname, hasLabel));
7910     if (*hasLabel) break;
7911     next = next->next;
7912   }
7913   PetscFunctionReturn(0);
7914 }
7915 
7916 /*@C
7917   DMGetLabel - Return the label of a given name, or NULL
7918 
7919   Not Collective
7920 
7921   Input Parameters:
7922 + dm   - The DM object
7923 - name - The label name
7924 
7925   Output Parameter:
7926 . label - The DMLabel, or NULL if the label is absent
7927 
7928   Note: Some of the default labels in a DMPlex will be
7929 $ "depth"       - Holds the depth (co-dimension) of each mesh point
7930 $ "celltype"    - Holds the topological type of each cell
7931 $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
7932 $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
7933 $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
7934 $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
7935 
7936   Level: intermediate
7937 
7938 .seealso: `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
7939 @*/
7940 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7941 {
7942   DMLabelLink    next = dm->labels;
7943   PetscBool      hasLabel;
7944   const char    *lname;
7945 
7946   PetscFunctionBegin;
7947   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7948   PetscValidCharPointer(name, 2);
7949   PetscValidPointer(label, 3);
7950   *label = NULL;
7951   while (next) {
7952     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
7953     PetscCall(PetscStrcmp(name, lname, &hasLabel));
7954     if (hasLabel) {
7955       *label = next->label;
7956       break;
7957     }
7958     next = next->next;
7959   }
7960   PetscFunctionReturn(0);
7961 }
7962 
7963 /*@C
7964   DMGetLabelByNum - Return the nth label
7965 
7966   Not Collective
7967 
7968   Input Parameters:
7969 + dm - The DM object
7970 - n  - the label number
7971 
7972   Output Parameter:
7973 . label - the label
7974 
7975   Level: intermediate
7976 
7977 .seealso: `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
7978 @*/
7979 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7980 {
7981   DMLabelLink next = dm->labels;
7982   PetscInt    l    = 0;
7983 
7984   PetscFunctionBegin;
7985   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7986   PetscValidPointer(label, 3);
7987   while (next) {
7988     if (l == n) {
7989       *label = next->label;
7990       PetscFunctionReturn(0);
7991     }
7992     ++l;
7993     next = next->next;
7994   }
7995   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n);
7996 }
7997 
7998 /*@C
7999   DMAddLabel - Add the label to this mesh
8000 
8001   Not Collective
8002 
8003   Input Parameters:
8004 + dm   - The DM object
8005 - label - The DMLabel
8006 
8007   Level: developer
8008 
8009 .seealso: `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
8010 @*/
8011 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
8012 {
8013   DMLabelLink    l, *p, tmpLabel;
8014   PetscBool      hasLabel;
8015   const char    *lname;
8016   PetscBool      flg;
8017 
8018   PetscFunctionBegin;
8019   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8020   PetscCall(PetscObjectGetName((PetscObject) label, &lname));
8021   PetscCall(DMHasLabel(dm, lname, &hasLabel));
8022   PetscCheck(!hasLabel,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
8023   PetscCall(PetscCalloc1(1, &tmpLabel));
8024   tmpLabel->label  = label;
8025   tmpLabel->output = PETSC_TRUE;
8026   for (p=&dm->labels; (l=*p); p=&l->next) {}
8027   *p = tmpLabel;
8028   PetscCall(PetscObjectReference((PetscObject)label));
8029   PetscCall(PetscStrcmp(lname, "depth", &flg));
8030   if (flg) dm->depthLabel = label;
8031   PetscCall(PetscStrcmp(lname, "celltype", &flg));
8032   if (flg) dm->celltypeLabel = label;
8033   PetscFunctionReturn(0);
8034 }
8035 
8036 /*@C
8037   DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present
8038 
8039   Not Collective
8040 
8041   Input Parameters:
8042 + dm    - The DM object
8043 - label - The DMLabel, having the same name, to substitute
8044 
8045   Note: Some of the default labels in a DMPlex will be
8046 $ "depth"       - Holds the depth (co-dimension) of each mesh point
8047 $ "celltype"    - Holds the topological type of each cell
8048 $ "ghost"       - If the DM is distributed with overlap, this marks the cells and faces in the overlap
8049 $ "Cell Sets"   - Mirrors the cell sets defined by GMsh and ExodusII
8050 $ "Face Sets"   - Mirrors the face sets defined by GMsh and ExodusII
8051 $ "Vertex Sets" - Mirrors the vertex sets defined by GMsh
8052 
8053   Level: intermediate
8054 
8055 .seealso: `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()`
8056 @*/
8057 PetscErrorCode DMSetLabel(DM dm, DMLabel label)
8058 {
8059   DMLabelLink    next = dm->labels;
8060   PetscBool      hasLabel, flg;
8061   const char    *name, *lname;
8062 
8063   PetscFunctionBegin;
8064   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8065   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
8066   PetscCall(PetscObjectGetName((PetscObject) label, &name));
8067   while (next) {
8068     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
8069     PetscCall(PetscStrcmp(name, lname, &hasLabel));
8070     if (hasLabel) {
8071       PetscCall(PetscObjectReference((PetscObject) label));
8072       PetscCall(PetscStrcmp(lname, "depth", &flg));
8073       if (flg) dm->depthLabel = label;
8074       PetscCall(PetscStrcmp(lname, "celltype", &flg));
8075       if (flg) dm->celltypeLabel = label;
8076       PetscCall(DMLabelDestroy(&next->label));
8077       next->label = label;
8078       break;
8079     }
8080     next = next->next;
8081   }
8082   PetscFunctionReturn(0);
8083 }
8084 
8085 /*@C
8086   DMRemoveLabel - Remove the label given by name from this mesh
8087 
8088   Not Collective
8089 
8090   Input Parameters:
8091 + dm   - The DM object
8092 - name - The label name
8093 
8094   Output Parameter:
8095 . label - The DMLabel, or NULL if the label is absent
8096 
8097   Level: developer
8098 
8099   Notes:
8100   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
8101   DMLabelDestroy() on the label.
8102 
8103   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
8104   call DMLabelDestroy(). Instead, the label is returned and the user is
8105   responsible of calling DMLabelDestroy() at some point.
8106 
8107 .seealso: `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()`
8108 @*/
8109 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
8110 {
8111   DMLabelLink    link, *pnext;
8112   PetscBool      hasLabel;
8113   const char    *lname;
8114 
8115   PetscFunctionBegin;
8116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8117   PetscValidCharPointer(name, 2);
8118   if (label) {
8119     PetscValidPointer(label, 3);
8120     *label = NULL;
8121   }
8122   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8123     PetscCall(PetscObjectGetName((PetscObject) link->label, &lname));
8124     PetscCall(PetscStrcmp(name, lname, &hasLabel));
8125     if (hasLabel) {
8126       *pnext = link->next; /* Remove from list */
8127       PetscCall(PetscStrcmp(name, "depth", &hasLabel));
8128       if (hasLabel) dm->depthLabel = NULL;
8129       PetscCall(PetscStrcmp(name, "celltype", &hasLabel));
8130       if (hasLabel) dm->celltypeLabel = NULL;
8131       if (label) *label = link->label;
8132       else       PetscCall(DMLabelDestroy(&link->label));
8133       PetscCall(PetscFree(link));
8134       break;
8135     }
8136   }
8137   PetscFunctionReturn(0);
8138 }
8139 
8140 /*@
8141   DMRemoveLabelBySelf - Remove the label from this mesh
8142 
8143   Not Collective
8144 
8145   Input Parameters:
8146 + dm   - The DM object
8147 . label - The DMLabel to be removed from the DM
8148 - failNotFound - Should it fail if the label is not found in the DM?
8149 
8150   Level: developer
8151 
8152   Notes:
8153   Only exactly the same instance is removed if found, name match is ignored.
8154   If the DM has an exclusive reference to the label, it gets destroyed and
8155   *label nullified.
8156 
8157 .seealso: `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()`
8158 @*/
8159 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
8160 {
8161   DMLabelLink    link, *pnext;
8162   PetscBool      hasLabel = PETSC_FALSE;
8163 
8164   PetscFunctionBegin;
8165   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8166   PetscValidPointer(label, 2);
8167   if (!*label && !failNotFound) PetscFunctionReturn(0);
8168   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
8169   PetscValidLogicalCollectiveBool(dm,failNotFound,3);
8170   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
8171     if (*label == link->label) {
8172       hasLabel = PETSC_TRUE;
8173       *pnext = link->next; /* Remove from list */
8174       if (*label == dm->depthLabel) dm->depthLabel = NULL;
8175       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
8176       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
8177       PetscCall(DMLabelDestroy(&link->label));
8178       PetscCall(PetscFree(link));
8179       break;
8180     }
8181   }
8182   PetscCheck(hasLabel || !failNotFound,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
8183   PetscFunctionReturn(0);
8184 }
8185 
8186 /*@C
8187   DMGetLabelOutput - Get the output flag for a given label
8188 
8189   Not Collective
8190 
8191   Input Parameters:
8192 + dm   - The DM object
8193 - name - The label name
8194 
8195   Output Parameter:
8196 . output - The flag for output
8197 
8198   Level: developer
8199 
8200 .seealso: `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
8201 @*/
8202 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
8203 {
8204   DMLabelLink    next = dm->labels;
8205   const char    *lname;
8206 
8207   PetscFunctionBegin;
8208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8209   PetscValidCharPointer(name, 2);
8210   PetscValidBoolPointer(output, 3);
8211   while (next) {
8212     PetscBool flg;
8213 
8214     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
8215     PetscCall(PetscStrcmp(name, lname, &flg));
8216     if (flg) {*output = next->output; PetscFunctionReturn(0);}
8217     next = next->next;
8218   }
8219   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8220 }
8221 
8222 /*@C
8223   DMSetLabelOutput - Set the output flag for a given label
8224 
8225   Not Collective
8226 
8227   Input Parameters:
8228 + dm     - The DM object
8229 . name   - The label name
8230 - output - The flag for output
8231 
8232   Level: developer
8233 
8234 .seealso: `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()`
8235 @*/
8236 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
8237 {
8238   DMLabelLink    next = dm->labels;
8239   const char    *lname;
8240 
8241   PetscFunctionBegin;
8242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8243   PetscValidCharPointer(name, 2);
8244   while (next) {
8245     PetscBool flg;
8246 
8247     PetscCall(PetscObjectGetName((PetscObject) next->label, &lname));
8248     PetscCall(PetscStrcmp(name, lname, &flg));
8249     if (flg) {next->output = output; PetscFunctionReturn(0);}
8250     next = next->next;
8251   }
8252   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
8253 }
8254 
8255 /*@
8256   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
8257 
8258   Collective on dmA
8259 
8260   Input Parameters:
8261 + dmA - The DM object with initial labels
8262 . dmB - The DM object to which labels are copied
8263 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
8264 . all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
8265 - emode - How to behave when a DMLabel in the source and destination DMs with the same name is encountered (see DMCopyLabelsMode)
8266 
8267   Level: intermediate
8268 
8269   Notes:
8270   This is typically used when interpolating or otherwise adding to a mesh, or testing.
8271 
8272 .seealso: `DMAddLabel()`, `DMCopyLabelsMode`
8273 @*/
8274 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode)
8275 {
8276   DMLabel        label, labelNew, labelOld;
8277   const char    *name;
8278   PetscBool      flg;
8279   DMLabelLink    link;
8280 
8281   PetscFunctionBegin;
8282   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
8283   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
8284   PetscValidLogicalCollectiveEnum(dmA, mode,3);
8285   PetscValidLogicalCollectiveBool(dmA, all, 4);
8286   PetscCheck(mode != PETSC_USE_POINTER,PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
8287   if (dmA == dmB) PetscFunctionReturn(0);
8288   for (link=dmA->labels; link; link=link->next) {
8289     label=link->label;
8290     PetscCall(PetscObjectGetName((PetscObject)label, &name));
8291     if (!all) {
8292       PetscCall(PetscStrcmp(name, "depth", &flg));
8293       if (flg) continue;
8294       PetscCall(PetscStrcmp(name, "dim", &flg));
8295       if (flg) continue;
8296       PetscCall(PetscStrcmp(name, "celltype", &flg));
8297       if (flg) continue;
8298     }
8299     PetscCall(DMGetLabel(dmB, name, &labelOld));
8300     if (labelOld) {
8301       switch (emode) {
8302         case DM_COPY_LABELS_KEEP:
8303           continue;
8304         case DM_COPY_LABELS_REPLACE:
8305           PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE));
8306           break;
8307         case DM_COPY_LABELS_FAIL:
8308           SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name);
8309         default:
8310           SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode);
8311       }
8312     }
8313     if (mode==PETSC_COPY_VALUES) {
8314       PetscCall(DMLabelDuplicate(label, &labelNew));
8315     } else {
8316       labelNew = label;
8317     }
8318     PetscCall(DMAddLabel(dmB, labelNew));
8319     if (mode==PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew));
8320   }
8321   PetscFunctionReturn(0);
8322 }
8323 
8324 /*@C
8325   DMCompareLabels - Compare labels of two DMPlex meshes
8326 
8327   Collective
8328 
8329   Input Parameters:
8330 + dm0 - First DM object
8331 - dm1 - Second DM object
8332 
8333   Output Parameters
8334 + equal   - (Optional) Flag whether labels of dm0 and dm1 are the same
8335 - message - (Optional) Message describing the difference, or NULL if there is no difference
8336 
8337   Level: intermediate
8338 
8339   Notes:
8340   The output flag equal is the same on all processes.
8341   If it is passed as NULL and difference is found, an error is thrown on all processes.
8342   Make sure to pass NULL on all processes.
8343 
8344   The output message is set independently on each rank.
8345   It is set to NULL if no difference was found on the current rank. It must be freed by user.
8346   If message is passed as NULL and difference is found, the difference description is printed to stderr in synchronized manner.
8347   Make sure to pass NULL on all processes.
8348 
8349   Labels are matched by name. If the number of labels and their names are equal,
8350   DMLabelCompare() is used to compare each pair of labels with the same name.
8351 
8352   Fortran Notes:
8353   This function is currently not available from Fortran.
8354 
8355 .seealso: `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()`
8356 @*/
8357 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message)
8358 {
8359   PetscInt        n, i;
8360   char            msg[PETSC_MAX_PATH_LEN] = "";
8361   PetscBool       eq;
8362   MPI_Comm        comm;
8363   PetscMPIInt     rank;
8364 
8365   PetscFunctionBegin;
8366   PetscValidHeaderSpecific(dm0,DM_CLASSID,1);
8367   PetscValidHeaderSpecific(dm1,DM_CLASSID,2);
8368   PetscCheckSameComm(dm0,1,dm1,2);
8369   if (equal) PetscValidBoolPointer(equal,3);
8370   if (message) PetscValidPointer(message, 4);
8371   PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm));
8372   PetscCallMPI(MPI_Comm_rank(comm, &rank));
8373   {
8374     PetscInt n1;
8375 
8376     PetscCall(DMGetNumLabels(dm0, &n));
8377     PetscCall(DMGetNumLabels(dm1, &n1));
8378     eq = (PetscBool) (n == n1);
8379     if (!eq) {
8380       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1));
8381     }
8382     PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
8383     if (!eq) goto finish;
8384   }
8385   for (i=0; i<n; i++) {
8386     DMLabel     l0, l1;
8387     const char *name;
8388     char       *msgInner;
8389 
8390     /* Ignore label order */
8391     PetscCall(DMGetLabelByNum(dm0, i, &l0));
8392     PetscCall(PetscObjectGetName((PetscObject)l0, &name));
8393     PetscCall(DMGetLabel(dm1, name, &l1));
8394     if (!l1) {
8395       PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i));
8396       eq = PETSC_FALSE;
8397       break;
8398     }
8399     PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner));
8400     PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg)));
8401     PetscCall(PetscFree(msgInner));
8402     if (!eq) break;
8403   }
8404   PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm));
8405 finish:
8406   /* If message output arg not set, print to stderr */
8407   if (message) {
8408     *message = NULL;
8409     if (msg[0]) {
8410       PetscCall(PetscStrallocpy(msg, message));
8411     }
8412   } else {
8413     if (msg[0]) {
8414       PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg));
8415     }
8416     PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR));
8417   }
8418   /* If same output arg not ser and labels are not equal, throw error */
8419   if (equal) *equal = eq;
8420   else PetscCheck(eq,comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1");
8421   PetscFunctionReturn(0);
8422 }
8423 
8424 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value)
8425 {
8426   PetscFunctionBegin;
8427   PetscValidPointer(label,2);
8428   if (!*label) {
8429     PetscCall(DMCreateLabel(dm, name));
8430     PetscCall(DMGetLabel(dm, name, label));
8431   }
8432   PetscCall(DMLabelSetValue(*label, point, value));
8433   PetscFunctionReturn(0);
8434 }
8435 
8436 /*
8437   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
8438   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
8439   (label, id) pair in the DM.
8440 
8441   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
8442   each label.
8443 */
8444 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
8445 {
8446   DMUniversalLabel ul;
8447   PetscBool       *active;
8448   PetscInt         pStart, pEnd, p, Nl, l, m;
8449 
8450   PetscFunctionBegin;
8451   PetscCall(PetscMalloc1(1, &ul));
8452   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label));
8453   PetscCall(DMGetNumLabels(dm, &Nl));
8454   PetscCall(PetscCalloc1(Nl, &active));
8455   ul->Nl = 0;
8456   for (l = 0; l < Nl; ++l) {
8457     PetscBool   isdepth, iscelltype;
8458     const char *name;
8459 
8460     PetscCall(DMGetLabelName(dm, l, &name));
8461     PetscCall(PetscStrncmp(name, "depth", 6, &isdepth));
8462     PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype));
8463     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
8464     if (active[l]) ++ul->Nl;
8465   }
8466   PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks));
8467   ul->Nv = 0;
8468   for (l = 0, m = 0; l < Nl; ++l) {
8469     DMLabel     label;
8470     PetscInt    nv;
8471     const char *name;
8472 
8473     if (!active[l]) continue;
8474     PetscCall(DMGetLabelName(dm, l, &name));
8475     PetscCall(DMGetLabelByNum(dm, l, &label));
8476     PetscCall(DMLabelGetNumValues(label, &nv));
8477     PetscCall(PetscStrallocpy(name, &ul->names[m]));
8478     ul->indices[m]   = l;
8479     ul->Nv          += nv;
8480     ul->offsets[m+1] = nv;
8481     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8482     ++m;
8483   }
8484   for (l = 1; l <= ul->Nl; ++l) {
8485     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8486     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8487   }
8488   for (l = 0; l < ul->Nl; ++l) {
8489     PetscInt b;
8490 
8491     ul->masks[l] = 0;
8492     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8493   }
8494   PetscCall(PetscMalloc1(ul->Nv, &ul->values));
8495   for (l = 0, m = 0; l < Nl; ++l) {
8496     DMLabel         label;
8497     IS              valueIS;
8498     const PetscInt *varr;
8499     PetscInt        nv, v;
8500 
8501     if (!active[l]) continue;
8502     PetscCall(DMGetLabelByNum(dm, l, &label));
8503     PetscCall(DMLabelGetNumValues(label, &nv));
8504     PetscCall(DMLabelGetValueIS(label, &valueIS));
8505     PetscCall(ISGetIndices(valueIS, &varr));
8506     for (v = 0; v < nv; ++v) {
8507       ul->values[ul->offsets[m]+v] = varr[v];
8508     }
8509     PetscCall(ISRestoreIndices(valueIS, &varr));
8510     PetscCall(ISDestroy(&valueIS));
8511     PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]]));
8512     ++m;
8513   }
8514   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
8515   for (p = pStart; p < pEnd; ++p) {
8516     PetscInt  uval = 0;
8517     PetscBool marked = PETSC_FALSE;
8518 
8519     for (l = 0, m = 0; l < Nl; ++l) {
8520       DMLabel  label;
8521       PetscInt val, defval, loc, nv;
8522 
8523       if (!active[l]) continue;
8524       PetscCall(DMGetLabelByNum(dm, l, &label));
8525       PetscCall(DMLabelGetValue(label, p, &val));
8526       PetscCall(DMLabelGetDefaultValue(label, &defval));
8527       if (val == defval) {++m; continue;}
8528       nv = ul->offsets[m+1]-ul->offsets[m];
8529       marked = PETSC_TRUE;
8530       PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc));
8531       PetscCheck(loc >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val);
8532       uval += (loc+1) << ul->bits[m];
8533       ++m;
8534     }
8535     if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval));
8536   }
8537   PetscCall(PetscFree(active));
8538   *universal = ul;
8539   PetscFunctionReturn(0);
8540 }
8541 
8542 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8543 {
8544   PetscInt       l;
8545 
8546   PetscFunctionBegin;
8547   for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l]));
8548   PetscCall(DMLabelDestroy(&(*universal)->label));
8549   PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks));
8550   PetscCall(PetscFree((*universal)->values));
8551   PetscCall(PetscFree(*universal));
8552   *universal = NULL;
8553   PetscFunctionReturn(0);
8554 }
8555 
8556 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8557 {
8558   PetscFunctionBegin;
8559   PetscValidPointer(ulabel, 2);
8560   *ulabel = ul->label;
8561   PetscFunctionReturn(0);
8562 }
8563 
8564 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8565 {
8566   PetscInt       Nl = ul->Nl, l;
8567 
8568   PetscFunctionBegin;
8569   PetscValidHeaderSpecific(dm, DM_CLASSID, 3);
8570   for (l = 0; l < Nl; ++l) {
8571     if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]));
8572     else               PetscCall(DMCreateLabel(dm, ul->names[l]));
8573   }
8574   if (preserveOrder) {
8575     for (l = 0; l < ul->Nl; ++l) {
8576       const char *name;
8577       PetscBool   match;
8578 
8579       PetscCall(DMGetLabelName(dm, ul->indices[l], &name));
8580       PetscCall(PetscStrcmp(name, ul->names[l], &match));
8581       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]);
8582     }
8583   }
8584   PetscFunctionReturn(0);
8585 }
8586 
8587 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8588 {
8589   PetscInt       l;
8590 
8591   PetscFunctionBegin;
8592   for (l = 0; l < ul->Nl; ++l) {
8593     DMLabel  label;
8594     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
8595 
8596     if (lval) {
8597       if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label));
8598       else          PetscCall(DMGetLabel(dm, ul->names[l], &label));
8599       PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]));
8600     }
8601   }
8602   PetscFunctionReturn(0);
8603 }
8604 
8605 /*@
8606   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
8607 
8608   Input Parameter:
8609 . dm - The DM object
8610 
8611   Output Parameter:
8612 . cdm - The coarse DM
8613 
8614   Level: intermediate
8615 
8616 .seealso: `DMSetCoarseDM()`
8617 @*/
8618 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8619 {
8620   PetscFunctionBegin;
8621   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8622   PetscValidPointer(cdm, 2);
8623   *cdm = dm->coarseMesh;
8624   PetscFunctionReturn(0);
8625 }
8626 
8627 /*@
8628   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
8629 
8630   Input Parameters:
8631 + dm - The DM object
8632 - cdm - The coarse DM
8633 
8634   Level: intermediate
8635 
8636 .seealso: `DMGetCoarseDM()`
8637 @*/
8638 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8639 {
8640   PetscFunctionBegin;
8641   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8642   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
8643   PetscCall(PetscObjectReference((PetscObject)cdm));
8644   PetscCall(DMDestroy(&dm->coarseMesh));
8645   dm->coarseMesh = cdm;
8646   PetscFunctionReturn(0);
8647 }
8648 
8649 /*@
8650   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
8651 
8652   Input Parameter:
8653 . dm - The DM object
8654 
8655   Output Parameter:
8656 . fdm - The fine DM
8657 
8658   Level: intermediate
8659 
8660 .seealso: `DMSetFineDM()`
8661 @*/
8662 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8663 {
8664   PetscFunctionBegin;
8665   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8666   PetscValidPointer(fdm, 2);
8667   *fdm = dm->fineMesh;
8668   PetscFunctionReturn(0);
8669 }
8670 
8671 /*@
8672   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
8673 
8674   Input Parameters:
8675 + dm - The DM object
8676 - fdm - The fine DM
8677 
8678   Level: intermediate
8679 
8680 .seealso: `DMGetFineDM()`
8681 @*/
8682 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8683 {
8684   PetscFunctionBegin;
8685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8686   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
8687   PetscCall(PetscObjectReference((PetscObject)fdm));
8688   PetscCall(DMDestroy(&dm->fineMesh));
8689   dm->fineMesh = fdm;
8690   PetscFunctionReturn(0);
8691 }
8692 
8693 /*=== DMBoundary code ===*/
8694 
8695 /*@C
8696   DMAddBoundary - Add a boundary condition to the model
8697 
8698   Collective on dm
8699 
8700   Input Parameters:
8701 + dm       - The DM, with a PetscDS that matches the problem being constrained
8702 . type     - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8703 . name     - The BC name
8704 . label    - The label defining constrained points
8705 . Nv       - The number of DMLabel values for constrained points
8706 . values   - An array of values for constrained points
8707 . field    - The field to constrain
8708 . Nc       - The number of constrained field components (0 will constrain all fields)
8709 . comps    - An array of constrained component numbers
8710 . bcFunc   - A pointwise function giving boundary values
8711 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL
8712 - ctx      - An optional user context for bcFunc
8713 
8714   Output Parameter:
8715 . bd          - (Optional) Boundary number
8716 
8717   Options Database Keys:
8718 + -bc_<boundary name> <num> - Overrides the boundary ids
8719 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8720 
8721   Note:
8722   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8723 
8724 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8725 
8726   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8727 
8728 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8729 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8730 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8731 $        PetscReal time, const PetscReal x[], PetscScalar bcval[])
8732 
8733 + dim - the spatial dimension
8734 . Nf - the number of fields
8735 . uOff - the offset into u[] and u_t[] for each field
8736 . uOff_x - the offset into u_x[] for each field
8737 . u - each field evaluated at the current point
8738 . u_t - the time derivative of each field evaluated at the current point
8739 . u_x - the gradient of each field evaluated at the current point
8740 . aOff - the offset into a[] and a_t[] for each auxiliary field
8741 . aOff_x - the offset into a_x[] for each auxiliary field
8742 . a - each auxiliary field evaluated at the current point
8743 . a_t - the time derivative of each auxiliary field evaluated at the current point
8744 . a_x - the gradient of auxiliary each field evaluated at the current point
8745 . t - current time
8746 . x - coordinates of the current point
8747 . numConstants - number of constant parameters
8748 . constants - constant parameters
8749 - bcval - output values at the current point
8750 
8751   Level: intermediate
8752 
8753 .seealso: `DSGetBoundary()`, `PetscDSAddBoundary()`
8754 @*/
8755 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)
8756 {
8757   PetscDS        ds;
8758 
8759   PetscFunctionBegin;
8760   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8761   PetscValidLogicalCollectiveEnum(dm, type, 2);
8762   PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4);
8763   PetscValidLogicalCollectiveInt(dm, Nv, 5);
8764   PetscValidLogicalCollectiveInt(dm, field, 7);
8765   PetscValidLogicalCollectiveInt(dm, Nc, 8);
8766   PetscCheck(!dm->localSection,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"Cannot add boundary to DM after creating local section");
8767   PetscCall(DMGetDS(dm, &ds));
8768   /* Complete label */
8769   if (label) {
8770     PetscObject  obj;
8771     PetscClassId id;
8772 
8773     PetscCall(DMGetField(dm, field, NULL, &obj));
8774     PetscCall(PetscObjectGetClassId(obj, &id));
8775     if (id == PETSCFE_CLASSID) {
8776       DM plex;
8777 
8778       PetscCall(DMConvert(dm, DMPLEX, &plex));
8779       if (plex) PetscCall(DMPlexLabelComplete(plex, label));
8780       PetscCall(DMDestroy(&plex));
8781     }
8782   }
8783   PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd));
8784   PetscFunctionReturn(0);
8785 }
8786 
8787 /* TODO Remove this since now the structures are the same */
8788 static PetscErrorCode DMPopulateBoundary(DM dm)
8789 {
8790   PetscDS        ds;
8791   DMBoundary    *lastnext;
8792   DSBoundary     dsbound;
8793 
8794   PetscFunctionBegin;
8795   PetscCall(DMGetDS(dm, &ds));
8796   dsbound = ds->boundary;
8797   if (dm->boundary) {
8798     DMBoundary next = dm->boundary;
8799 
8800     /* quick check to see if the PetscDS has changed */
8801     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
8802     /* the PetscDS has changed: tear down and rebuild */
8803     while (next) {
8804       DMBoundary b = next;
8805 
8806       next = b->next;
8807       PetscCall(PetscFree(b));
8808     }
8809     dm->boundary = NULL;
8810   }
8811 
8812   lastnext = &(dm->boundary);
8813   while (dsbound) {
8814     DMBoundary dmbound;
8815 
8816     PetscCall(PetscNew(&dmbound));
8817     dmbound->dsboundary = dsbound;
8818     dmbound->label      = dsbound->label;
8819     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8820     *lastnext = dmbound;
8821     lastnext = &(dmbound->next);
8822     dsbound = dsbound->next;
8823   }
8824   PetscFunctionReturn(0);
8825 }
8826 
8827 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8828 {
8829   DMBoundary     b;
8830 
8831   PetscFunctionBegin;
8832   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8833   PetscValidBoolPointer(isBd, 3);
8834   *isBd = PETSC_FALSE;
8835   PetscCall(DMPopulateBoundary(dm));
8836   b = dm->boundary;
8837   while (b && !(*isBd)) {
8838     DMLabel    label = b->label;
8839     DSBoundary dsb   = b->dsboundary;
8840     PetscInt   i;
8841 
8842     if (label) {
8843       for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd));
8844     }
8845     b = b->next;
8846   }
8847   PetscFunctionReturn(0);
8848 }
8849 
8850 /*@C
8851   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8852 
8853   Collective on DM
8854 
8855   Input Parameters:
8856 + dm      - The DM
8857 . time    - The time
8858 . funcs   - The coordinate functions to evaluate, one per field
8859 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8860 - mode    - The insertion mode for values
8861 
8862   Output Parameter:
8863 . X - vector
8864 
8865    Calling sequence of func:
8866 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8867 
8868 +  dim - The spatial dimension
8869 .  time - The time at which to sample
8870 .  x   - The coordinates
8871 .  Nc  - The number of components
8872 .  u   - The output field values
8873 -  ctx - optional user-defined function context
8874 
8875   Level: developer
8876 
8877 .seealso: `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8878 @*/
8879 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8880 {
8881   Vec            localX;
8882 
8883   PetscFunctionBegin;
8884   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8885   PetscCall(DMGetLocalVector(dm, &localX));
8886   PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX));
8887   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8888   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8889   PetscCall(DMRestoreLocalVector(dm, &localX));
8890   PetscFunctionReturn(0);
8891 }
8892 
8893 /*@C
8894   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8895 
8896   Not collective
8897 
8898   Input Parameters:
8899 + dm      - The DM
8900 . time    - The time
8901 . funcs   - The coordinate functions to evaluate, one per field
8902 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8903 - mode    - The insertion mode for values
8904 
8905   Output Parameter:
8906 . localX - vector
8907 
8908    Calling sequence of func:
8909 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8910 
8911 +  dim - The spatial dimension
8912 .  x   - The coordinates
8913 .  Nc  - The number of components
8914 .  u   - The output field values
8915 -  ctx - optional user-defined function context
8916 
8917   Level: developer
8918 
8919 .seealso: `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
8920 @*/
8921 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8922 {
8923   PetscFunctionBegin;
8924   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8925   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
8926   PetscCheck(dm->ops->projectfunctionlocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8927   PetscCall((dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX));
8928   PetscFunctionReturn(0);
8929 }
8930 
8931 /*@C
8932   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.
8933 
8934   Collective on DM
8935 
8936   Input Parameters:
8937 + dm      - The DM
8938 . time    - The time
8939 . label   - The DMLabel selecting the portion of the mesh for projection
8940 . funcs   - The coordinate functions to evaluate, one per field
8941 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8942 - mode    - The insertion mode for values
8943 
8944   Output Parameter:
8945 . X - vector
8946 
8947    Calling sequence of func:
8948 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8949 
8950 +  dim - The spatial dimension
8951 .  x   - The coordinates
8952 .  Nc  - The number of components
8953 .  u   - The output field values
8954 -  ctx - optional user-defined function context
8955 
8956   Level: developer
8957 
8958 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()`
8959 @*/
8960 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)
8961 {
8962   Vec            localX;
8963 
8964   PetscFunctionBegin;
8965   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8966   PetscCall(DMGetLocalVector(dm, &localX));
8967   PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
8968   PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X));
8969   PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X));
8970   PetscCall(DMRestoreLocalVector(dm, &localX));
8971   PetscFunctionReturn(0);
8972 }
8973 
8974 /*@C
8975   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.
8976 
8977   Not collective
8978 
8979   Input Parameters:
8980 + dm      - The DM
8981 . time    - The time
8982 . label   - The DMLabel selecting the portion of the mesh for projection
8983 . funcs   - The coordinate functions to evaluate, one per field
8984 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8985 - mode    - The insertion mode for values
8986 
8987   Output Parameter:
8988 . localX - vector
8989 
8990    Calling sequence of func:
8991 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar u[], void *ctx);
8992 
8993 +  dim - The spatial dimension
8994 .  x   - The coordinates
8995 .  Nc  - The number of components
8996 .  u   - The output field values
8997 -  ctx - optional user-defined function context
8998 
8999   Level: developer
9000 
9001 .seealso: `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()`
9002 @*/
9003 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)
9004 {
9005   PetscFunctionBegin;
9006   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9007   PetscValidHeaderSpecific(localX,VEC_CLASSID,11);
9008   PetscCheck(dm->ops->projectfunctionlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
9009   PetscCall((dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX));
9010   PetscFunctionReturn(0);
9011 }
9012 
9013 /*@C
9014   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
9015 
9016   Not collective
9017 
9018   Input Parameters:
9019 + dm      - The DM
9020 . time    - The time
9021 . localU  - The input field vector
9022 . funcs   - The functions to evaluate, one per field
9023 - mode    - The insertion mode for values
9024 
9025   Output Parameter:
9026 . localX  - The output vector
9027 
9028    Calling sequence of func:
9029 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9030 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9031 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9032 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
9033 
9034 +  dim          - The spatial dimension
9035 .  Nf           - The number of input fields
9036 .  NfAux        - The number of input auxiliary fields
9037 .  uOff         - The offset of each field in u[]
9038 .  uOff_x       - The offset of each field in u_x[]
9039 .  u            - The field values at this point in space
9040 .  u_t          - The field time derivative at this point in space (or NULL)
9041 .  u_x          - The field derivatives at this point in space
9042 .  aOff         - The offset of each auxiliary field in u[]
9043 .  aOff_x       - The offset of each auxiliary field in u_x[]
9044 .  a            - The auxiliary field values at this point in space
9045 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
9046 .  a_x          - The auxiliary field derivatives at this point in space
9047 .  t            - The current time
9048 .  x            - The coordinates of this point
9049 .  numConstants - The number of constants
9050 .  constants    - The value of each constant
9051 -  f            - The value of the function at this point in space
9052 
9053   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.
9054   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
9055   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
9056   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
9057 
9058   Level: intermediate
9059 
9060 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
9061 @*/
9062 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
9063                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
9064                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9065                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9066                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9067                                    InsertMode mode, Vec localX)
9068 {
9069   PetscFunctionBegin;
9070   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9071   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
9072   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
9073   PetscCheck(dm->ops->projectfieldlocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
9074   PetscCall((dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX));
9075   PetscFunctionReturn(0);
9076 }
9077 
9078 /*@C
9079   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.
9080 
9081   Not collective
9082 
9083   Input Parameters:
9084 + dm      - The DM
9085 . time    - The time
9086 . label   - The DMLabel marking the portion of the domain to output
9087 . numIds  - The number of label ids to use
9088 . ids     - The label ids to use for marking
9089 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
9090 . comps   - The components to set in the output, or NULL for all components
9091 . localU  - The input field vector
9092 . funcs   - The functions to evaluate, one per field
9093 - mode    - The insertion mode for values
9094 
9095   Output Parameter:
9096 . localX  - The output vector
9097 
9098    Calling sequence of func:
9099 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9100 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9101 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9102 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
9103 
9104 +  dim          - The spatial dimension
9105 .  Nf           - The number of input fields
9106 .  NfAux        - The number of input auxiliary fields
9107 .  uOff         - The offset of each field in u[]
9108 .  uOff_x       - The offset of each field in u_x[]
9109 .  u            - The field values at this point in space
9110 .  u_t          - The field time derivative at this point in space (or NULL)
9111 .  u_x          - The field derivatives at this point in space
9112 .  aOff         - The offset of each auxiliary field in u[]
9113 .  aOff_x       - The offset of each auxiliary field in u_x[]
9114 .  a            - The auxiliary field values at this point in space
9115 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
9116 .  a_x          - The auxiliary field derivatives at this point in space
9117 .  t            - The current time
9118 .  x            - The coordinates of this point
9119 .  numConstants - The number of constants
9120 .  constants    - The value of each constant
9121 -  f            - The value of the function at this point in space
9122 
9123   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.
9124   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
9125   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
9126   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
9127 
9128   Level: intermediate
9129 
9130 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
9131 @*/
9132 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
9133                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
9134                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9135                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9136                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9137                                         InsertMode mode, Vec localX)
9138 {
9139   PetscFunctionBegin;
9140   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9141   PetscValidHeaderSpecific(localU,VEC_CLASSID,8);
9142   PetscValidHeaderSpecific(localX,VEC_CLASSID,11);
9143   PetscCheck(dm->ops->projectfieldlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
9144   PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
9145   PetscFunctionReturn(0);
9146 }
9147 
9148 /*@C
9149   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.
9150 
9151   Not collective
9152 
9153   Input Parameters:
9154 + dm      - The DM
9155 . time    - The time
9156 . label   - The DMLabel marking the portion of the domain boundary to output
9157 . numIds  - The number of label ids to use
9158 . ids     - The label ids to use for marking
9159 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
9160 . comps   - The components to set in the output, or NULL for all components
9161 . localU  - The input field vector
9162 . funcs   - The functions to evaluate, one per field
9163 - mode    - The insertion mode for values
9164 
9165   Output Parameter:
9166 . localX  - The output vector
9167 
9168    Calling sequence of func:
9169 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
9170 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
9171 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
9172 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
9173 
9174 +  dim          - The spatial dimension
9175 .  Nf           - The number of input fields
9176 .  NfAux        - The number of input auxiliary fields
9177 .  uOff         - The offset of each field in u[]
9178 .  uOff_x       - The offset of each field in u_x[]
9179 .  u            - The field values at this point in space
9180 .  u_t          - The field time derivative at this point in space (or NULL)
9181 .  u_x          - The field derivatives at this point in space
9182 .  aOff         - The offset of each auxiliary field in u[]
9183 .  aOff_x       - The offset of each auxiliary field in u_x[]
9184 .  a            - The auxiliary field values at this point in space
9185 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
9186 .  a_x          - The auxiliary field derivatives at this point in space
9187 .  t            - The current time
9188 .  x            - The coordinates of this point
9189 .  n            - The face normal
9190 .  numConstants - The number of constants
9191 .  constants    - The value of each constant
9192 -  f            - The value of the function at this point in space
9193 
9194   Note:
9195   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
9196   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
9197   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
9198   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
9199 
9200   Level: intermediate
9201 
9202 .seealso: `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()`
9203 @*/
9204 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
9205                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
9206                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9207                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
9208                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
9209                                           InsertMode mode, Vec localX)
9210 {
9211   PetscFunctionBegin;
9212   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9213   PetscValidHeaderSpecific(localU,VEC_CLASSID,8);
9214   PetscValidHeaderSpecific(localX,VEC_CLASSID,11);
9215   PetscCheck(dm->ops->projectbdfieldlabellocal,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
9216   PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX));
9217   PetscFunctionReturn(0);
9218 }
9219 
9220 /*@C
9221   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
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 diff ||u - u_h||_2
9232 
9233   Level: developer
9234 
9235 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
9236 @*/
9237 PetscErrorCode DMComputeL2Diff(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->computel2diff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
9243   PetscCall((dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff));
9244   PetscFunctionReturn(0);
9245 }
9246 
9247 /*@C
9248   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
9249 
9250   Collective on dm
9251 
9252   Input Parameters:
9253 + dm    - The DM
9254 , time  - The time
9255 . funcs - The gradient functions to evaluate for each field component
9256 . ctxs  - Optional array of contexts to pass to each function, or NULL.
9257 . X     - The coefficient vector u_h, a global vector
9258 - n     - The vector to project along
9259 
9260   Output Parameter:
9261 . diff - The diff ||(grad u - grad u_h) . n||_2
9262 
9263   Level: developer
9264 
9265 .seealso: `DMProjectFunction()`, `DMComputeL2Diff()`
9266 @*/
9267 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)
9268 {
9269   PetscFunctionBegin;
9270   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9271   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
9272   PetscCheck(dm->ops->computel2gradientdiff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
9273   PetscCall((dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff));
9274   PetscFunctionReturn(0);
9275 }
9276 
9277 /*@C
9278   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
9279 
9280   Collective on dm
9281 
9282   Input Parameters:
9283 + dm    - The DM
9284 . time  - The time
9285 . funcs - The functions to evaluate for each field component
9286 . ctxs  - Optional array of contexts to pass to each function, or NULL.
9287 - X     - The coefficient vector u_h, a global vector
9288 
9289   Output Parameter:
9290 . diff - The array of differences, ||u^f - u^f_h||_2
9291 
9292   Level: developer
9293 
9294 .seealso: `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()`
9295 @*/
9296 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
9297 {
9298   PetscFunctionBegin;
9299   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9300   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
9301   PetscCheck(dm->ops->computel2fielddiff,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
9302   PetscCall((dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff));
9303   PetscFunctionReturn(0);
9304 }
9305 
9306 /*@C
9307  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
9308 
9309  Not Collective
9310 
9311  Input Parameter:
9312 .  dm    - The DM
9313 
9314  Output Parameters:
9315 +  nranks - the number of neighbours
9316 -  ranks - the neighbors ranks
9317 
9318  Notes:
9319  Do not free the array, it is freed when the DM is destroyed.
9320 
9321  Level: beginner
9322 
9323  .seealso: `DMDAGetNeighbors()`, `PetscSFGetRootRanks()`
9324 @*/
9325 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9326 {
9327   PetscFunctionBegin;
9328   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9329   PetscCheck(dm->ops->getneighbors,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9330   PetscCall((dm->ops->getneighbors)(dm,nranks,ranks));
9331   PetscFunctionReturn(0);
9332 }
9333 
9334 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
9335 
9336 /*
9337     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9338     This has be a different function because it requires DM which is not defined in the Mat library
9339 */
9340 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9341 {
9342   PetscFunctionBegin;
9343   if (coloring->ctype == IS_COLORING_LOCAL) {
9344     Vec x1local;
9345     DM  dm;
9346     PetscCall(MatGetDM(J,&dm));
9347     PetscCheck(dm,PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9348     PetscCall(DMGetLocalVector(dm,&x1local));
9349     PetscCall(DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local));
9350     PetscCall(DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local));
9351     x1   = x1local;
9352   }
9353   PetscCall(MatFDColoringApply_AIJ(J,coloring,x1,sctx));
9354   if (coloring->ctype == IS_COLORING_LOCAL) {
9355     DM  dm;
9356     PetscCall(MatGetDM(J,&dm));
9357     PetscCall(DMRestoreLocalVector(dm,&x1));
9358   }
9359   PetscFunctionReturn(0);
9360 }
9361 
9362 /*@
9363     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
9364 
9365     Input Parameter:
9366 .    coloring - the MatFDColoring object
9367 
9368     Developer Notes:
9369     this routine exists because the PETSc Mat library does not know about the DM objects
9370 
9371     Level: advanced
9372 
9373 .seealso: `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType`
9374 @*/
9375 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9376 {
9377   PetscFunctionBegin;
9378   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9379   PetscFunctionReturn(0);
9380 }
9381 
9382 /*@
9383     DMGetCompatibility - determine if two DMs are compatible
9384 
9385     Collective
9386 
9387     Input Parameters:
9388 +    dm1 - the first DM
9389 -    dm2 - the second DM
9390 
9391     Output Parameters:
9392 +    compatible - whether or not the two DMs are compatible
9393 -    set - whether or not the compatible value was set
9394 
9395     Notes:
9396     Two DMs are deemed compatible if they represent the same parallel decomposition
9397     of the same topology. This implies that the section (field data) on one
9398     "makes sense" with respect to the topology and parallel decomposition of the other.
9399     Loosely speaking, compatible DMs represent the same domain and parallel
9400     decomposition, but hold different data.
9401 
9402     Typically, one would confirm compatibility if intending to simultaneously iterate
9403     over a pair of vectors obtained from different DMs.
9404 
9405     For example, two DMDA objects are compatible if they have the same local
9406     and global sizes and the same stencil width. They can have different numbers
9407     of degrees of freedom per node. Thus, one could use the node numbering from
9408     either DM in bounds for a loop over vectors derived from either DM.
9409 
9410     Consider the operation of summing data living on a 2-dof DMDA to data living
9411     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9412 .vb
9413   ...
9414   PetscCall(DMGetCompatibility(da1,da2,&compatible,&set));
9415   if (set && compatible)  {
9416     PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1));
9417     PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2));
9418     PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL));
9419     for (j=y; j<y+n; ++j) {
9420       for (i=x; i<x+m, ++i) {
9421         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9422       }
9423     }
9424     PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1));
9425     PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2));
9426   } else {
9427     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9428   }
9429   ...
9430 .ve
9431 
9432     Checking compatibility might be expensive for a given implementation of DM,
9433     or might be impossible to unambiguously confirm or deny. For this reason,
9434     this function may decline to determine compatibility, and hence users should
9435     always check the "set" output parameter.
9436 
9437     A DM is always compatible with itself.
9438 
9439     In the current implementation, DMs which live on "unequal" communicators
9440     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9441     incompatible.
9442 
9443     This function is labeled "Collective," as information about all subdomains
9444     is required on each rank. However, in DM implementations which store all this
9445     information locally, this function may be merely "Logically Collective".
9446 
9447     Developer Notes:
9448     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9449     iff B is compatible with A. Thus, this function checks the implementations
9450     of both dm and dmc (if they are of different types), attempting to determine
9451     compatibility. It is left to DM implementers to ensure that symmetry is
9452     preserved. The simplest way to do this is, when implementing type-specific
9453     logic for this function, is to check for existing logic in the implementation
9454     of other DM types and let *set = PETSC_FALSE if found.
9455 
9456     Level: advanced
9457 
9458 .seealso: `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()`
9459 @*/
9460 
9461 PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9462 {
9463   PetscMPIInt    compareResult;
9464   DMType         type,type2;
9465   PetscBool      sameType;
9466 
9467   PetscFunctionBegin;
9468   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
9469   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
9470 
9471   /* Declare a DM compatible with itself */
9472   if (dm1 == dm2) {
9473     *set = PETSC_TRUE;
9474     *compatible = PETSC_TRUE;
9475     PetscFunctionReturn(0);
9476   }
9477 
9478   /* Declare a DM incompatible with a DM that lives on an "unequal"
9479      communicator. Note that this does not preclude compatibility with
9480      DMs living on "congruent" or "similar" communicators, but this must be
9481      determined by the implementation-specific logic */
9482   PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult));
9483   if (compareResult == MPI_UNEQUAL) {
9484     *set = PETSC_TRUE;
9485     *compatible = PETSC_FALSE;
9486     PetscFunctionReturn(0);
9487   }
9488 
9489   /* Pass to the implementation-specific routine, if one exists. */
9490   if (dm1->ops->getcompatibility) {
9491     PetscCall((*dm1->ops->getcompatibility)(dm1,dm2,compatible,set));
9492     if (*set) PetscFunctionReturn(0);
9493   }
9494 
9495   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9496      with an implementation of this function from dm2 */
9497   PetscCall(DMGetType(dm1,&type));
9498   PetscCall(DMGetType(dm2,&type2));
9499   PetscCall(PetscStrcmp(type,type2,&sameType));
9500   if (!sameType && dm2->ops->getcompatibility) {
9501     PetscCall((*dm2->ops->getcompatibility)(dm2,dm1,compatible,set)); /* Note argument order */
9502   } else {
9503     *set = PETSC_FALSE;
9504   }
9505   PetscFunctionReturn(0);
9506 }
9507 
9508 /*@C
9509   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
9510 
9511   Logically Collective on DM
9512 
9513   Input Parameters:
9514 + DM - the DM
9515 . f - the monitor function
9516 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9517 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
9518 
9519   Options Database Keys:
9520 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9521                             does not cancel those set via the options database.
9522 
9523   Notes:
9524   Several different monitoring routines may be set by calling
9525   DMMonitorSet() multiple times; all will be called in the
9526   order in which they were set.
9527 
9528   Fortran Notes:
9529   Only a single monitor function can be set for each DM object
9530 
9531   Level: intermediate
9532 
9533 .seealso: `DMMonitorCancel()`
9534 @*/
9535 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9536 {
9537   PetscInt       m;
9538 
9539   PetscFunctionBegin;
9540   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9541   for (m = 0; m < dm->numbermonitors; ++m) {
9542     PetscBool identical;
9543 
9544     PetscCall(PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical));
9545     if (identical) PetscFunctionReturn(0);
9546   }
9547   PetscCheck(dm->numbermonitors < MAXDMMONITORS,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9548   dm->monitor[dm->numbermonitors]          = f;
9549   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9550   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9551   PetscFunctionReturn(0);
9552 }
9553 
9554 /*@
9555   DMMonitorCancel - Clears all the monitor functions for a DM object.
9556 
9557   Logically Collective on DM
9558 
9559   Input Parameter:
9560 . dm - the DM
9561 
9562   Options Database Key:
9563 . -dm_monitor_cancel - cancels all monitors that have been hardwired
9564   into a code by calls to DMonitorSet(), but does not cancel those
9565   set via the options database
9566 
9567   Notes:
9568   There is no way to clear one specific monitor from a DM object.
9569 
9570   Level: intermediate
9571 
9572 .seealso: `DMMonitorSet()`
9573 @*/
9574 PetscErrorCode DMMonitorCancel(DM dm)
9575 {
9576   PetscInt       m;
9577 
9578   PetscFunctionBegin;
9579   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9580   for (m = 0; m < dm->numbermonitors; ++m) {
9581     if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m]));
9582   }
9583   dm->numbermonitors = 0;
9584   PetscFunctionReturn(0);
9585 }
9586 
9587 /*@C
9588   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9589 
9590   Collective on DM
9591 
9592   Input Parameters:
9593 + dm   - DM object you wish to monitor
9594 . name - the monitor type one is seeking
9595 . help - message indicating what monitoring is done
9596 . manual - manual page for the monitor
9597 . monitor - the monitor function
9598 - 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
9599 
9600   Output Parameter:
9601 . flg - Flag set if the monitor was created
9602 
9603   Level: developer
9604 
9605 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`,
9606           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
9607           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, `PetscOptionsBool()`,
9608           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
9609           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
9610           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
9611           `PetscOptionsFList()`, `PetscOptionsEList()`
9612 @*/
9613 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9614 {
9615   PetscViewer       viewer;
9616   PetscViewerFormat format;
9617 
9618   PetscFunctionBegin;
9619   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9620   PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg));
9621   if (*flg) {
9622     PetscViewerAndFormat *vf;
9623 
9624     PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf));
9625     PetscCall(PetscObjectDereference((PetscObject) viewer));
9626     if (monitorsetup) PetscCall((*monitorsetup)(dm, vf));
9627     PetscCall(DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy));
9628   }
9629   PetscFunctionReturn(0);
9630 }
9631 
9632 /*@
9633    DMMonitor - runs the user provided monitor routines, if they exist
9634 
9635    Collective on DM
9636 
9637    Input Parameters:
9638 .  dm - The DM
9639 
9640    Level: developer
9641 
9642 .seealso: `DMMonitorSet()`
9643 @*/
9644 PetscErrorCode DMMonitor(DM dm)
9645 {
9646   PetscInt       m;
9647 
9648   PetscFunctionBegin;
9649   if (!dm) PetscFunctionReturn(0);
9650   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9651   for (m = 0; m < dm->numbermonitors; ++m) {
9652     PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m]));
9653   }
9654   PetscFunctionReturn(0);
9655 }
9656 
9657 /*@
9658   DMComputeError - Computes the error assuming the user has given exact solution functions
9659 
9660   Collective on DM
9661 
9662   Input Parameters:
9663 + dm     - The DM
9664 - sol    - The solution vector
9665 
9666   Input/Output Parameter:
9667 . errors - An array of length Nf, the number of fields, or NULL for no output; on output
9668            contains the error in each field
9669 
9670   Output Parameter:
9671 . errorVec - A vector to hold the cellwise error (may be NULL)
9672 
9673   Note: The exact solutions come from the PetscDS object, and the time comes from DMGetOutputSequenceNumber().
9674 
9675   Level: developer
9676 
9677 .seealso: `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()`
9678 @*/
9679 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec)
9680 {
9681   PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *);
9682   void            **ctxs;
9683   PetscReal         time;
9684   PetscInt          Nf, f, Nds, s;
9685 
9686   PetscFunctionBegin;
9687   PetscCall(DMGetNumFields(dm, &Nf));
9688   PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs));
9689   PetscCall(DMGetNumDS(dm, &Nds));
9690   for (s = 0; s < Nds; ++s) {
9691     PetscDS         ds;
9692     DMLabel         label;
9693     IS              fieldIS;
9694     const PetscInt *fields;
9695     PetscInt        dsNf;
9696 
9697     PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds));
9698     PetscCall(PetscDSGetNumFields(ds, &dsNf));
9699     if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields));
9700     for (f = 0; f < dsNf; ++f) {
9701       const PetscInt field = fields[f];
9702       PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field]));
9703     }
9704     if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields));
9705   }
9706   for (f = 0; f < Nf; ++f) {
9707     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);
9708   }
9709   PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time));
9710   if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors));
9711   if (errorVec) {
9712     DM             edm;
9713     DMPolytopeType ct;
9714     PetscBool      simplex;
9715     PetscInt       dim, cStart, Nf;
9716 
9717     PetscCall(DMClone(dm, &edm));
9718     PetscCall(DMGetDimension(edm, &dim));
9719     PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL));
9720     PetscCall(DMPlexGetCellType(dm, cStart, &ct));
9721     simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
9722     PetscCall(DMGetNumFields(dm, &Nf));
9723     for (f = 0; f < Nf; ++f) {
9724       PetscFE         fe, efe;
9725       PetscQuadrature q;
9726       const char     *name;
9727 
9728       PetscCall(DMGetField(dm, f, NULL, (PetscObject *) &fe));
9729       PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe));
9730       PetscCall(PetscObjectGetName((PetscObject) fe, &name));
9731       PetscCall(PetscObjectSetName((PetscObject) efe, name));
9732       PetscCall(PetscFEGetQuadrature(fe, &q));
9733       PetscCall(PetscFESetQuadrature(efe, q));
9734       PetscCall(DMSetField(edm, f, NULL, (PetscObject) efe));
9735       PetscCall(PetscFEDestroy(&efe));
9736     }
9737     PetscCall(DMCreateDS(edm));
9738 
9739     PetscCall(DMCreateGlobalVector(edm, errorVec));
9740     PetscCall(PetscObjectSetName((PetscObject) *errorVec, "Error"));
9741     PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec));
9742     PetscCall(DMDestroy(&edm));
9743   }
9744   PetscCall(PetscFree2(exactSol, ctxs));
9745   PetscFunctionReturn(0);
9746 }
9747 
9748 /*@
9749   DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this DM
9750 
9751   Not collective
9752 
9753   Input Parameter:
9754 . dm     - The DM
9755 
9756   Output Parameter:
9757 . numAux - The number of auxiliary data vectors
9758 
9759   Level: advanced
9760 
9761 .seealso: `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9762 @*/
9763 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux)
9764 {
9765   PetscFunctionBegin;
9766   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9767   PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux));
9768   PetscFunctionReturn(0);
9769 }
9770 
9771 /*@
9772   DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part
9773 
9774   Not collective
9775 
9776   Input Parameters:
9777 + dm     - The DM
9778 . label  - The DMLabel
9779 . value  - The label value indicating the region
9780 - part   - The equation part, or 0 if unused
9781 
9782   Output Parameter:
9783 . aux    - The Vec holding auxiliary field data
9784 
9785   Note: If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well.
9786 
9787   Level: advanced
9788 
9789 .seealso: `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`
9790 @*/
9791 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux)
9792 {
9793   PetscHashAuxKey key, wild = {NULL, 0, 0};
9794   PetscBool       has;
9795 
9796   PetscFunctionBegin;
9797   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9798   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9799   key.label = label;
9800   key.value = value;
9801   key.part  = part;
9802   PetscCall(PetscHMapAuxHas(dm->auxData, key, &has));
9803   if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key,  aux));
9804   else     PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux));
9805   PetscFunctionReturn(0);
9806 }
9807 
9808 /*@
9809   DMSetAuxiliaryVec - Set the auxiliary vector for region specified by the given label and value, and equation part
9810 
9811   Not collective
9812 
9813   Input Parameters:
9814 + dm     - The DM
9815 . label  - The DMLabel
9816 . value  - The label value indicating the region
9817 . part   - The equation part, or 0 if unused
9818 - aux    - The Vec holding auxiliary field data
9819 
9820   Level: advanced
9821 
9822 .seealso: `DMGetAuxiliaryVec()`
9823 @*/
9824 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux)
9825 {
9826   Vec             old;
9827   PetscHashAuxKey key;
9828 
9829   PetscFunctionBegin;
9830   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9831   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
9832   key.label = label;
9833   key.value = value;
9834   key.part  = part;
9835   PetscCall(PetscHMapAuxGet(dm->auxData, key, &old));
9836   PetscCall(PetscObjectReference((PetscObject) aux));
9837   PetscCall(PetscObjectDereference((PetscObject) old));
9838   if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key));
9839   else      PetscCall(PetscHMapAuxSet(dm->auxData, key, aux));
9840   PetscFunctionReturn(0);
9841 }
9842 
9843 /*@C
9844   DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this DM
9845 
9846   Not collective
9847 
9848   Input Parameter:
9849 . dm      - The DM
9850 
9851   Output Parameters:
9852 + labels  - The DMLabels for each Vec
9853 . values  - The label values for each Vec
9854 - parts   - The equation parts for each Vec
9855 
9856   Note: The arrays passed in must be at least as large as DMGetNumAuxiliaryVec().
9857 
9858   Level: advanced
9859 
9860 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9861 @*/
9862 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[])
9863 {
9864   PetscHashAuxKey *keys;
9865   PetscInt         n, i, off = 0;
9866 
9867   PetscFunctionBegin;
9868   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9869   PetscValidPointer(labels, 2);
9870   PetscValidIntPointer(values, 3);
9871   PetscValidIntPointer(parts,  4);
9872   PetscCall(DMGetNumAuxiliaryVec(dm, &n));
9873   PetscCall(PetscMalloc1(n, &keys));
9874   PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys));
9875   for (i = 0; i < n; ++i) {labels[i] = keys[i].label; values[i] = keys[i].value; parts[i] = keys[i].part;}
9876   PetscCall(PetscFree(keys));
9877   PetscFunctionReturn(0);
9878 }
9879 
9880 /*@
9881   DMCopyAuxiliaryVec - Copy the auxiliary data to a new DM
9882 
9883   Not collective
9884 
9885   Input Parameter:
9886 . dm    - The DM
9887 
9888   Output Parameter:
9889 . dmNew - The new DM, now with the same auxiliary data
9890 
9891   Level: advanced
9892 
9893 .seealso: `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`
9894 @*/
9895 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew)
9896 {
9897   PetscFunctionBegin;
9898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9899   PetscCall(PetscHMapAuxDestroy(&dmNew->auxData));
9900   PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData));
9901   PetscFunctionReturn(0);
9902 }
9903 
9904 /*@C
9905   DMPolytopeMatchOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement
9906 
9907   Not collective
9908 
9909   Input Parameters:
9910 + ct         - The DMPolytopeType
9911 . sourceCone - The source arrangement of faces
9912 - targetCone - The target arrangement of faces
9913 
9914   Output Parameters:
9915 + ornt  - The orientation which will take the source arrangement to the target arrangement
9916 - found - Flag indicating that a suitable orientation was found
9917 
9918   Level: advanced
9919 
9920 .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`
9921 @*/
9922 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found)
9923 {
9924   const PetscInt cS = DMPolytopeTypeGetConeSize(ct);
9925   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9926   PetscInt       o, c;
9927 
9928   PetscFunctionBegin;
9929   if (!nO) {*ornt = 0; *found = PETSC_TRUE; PetscFunctionReturn(0);}
9930   for (o = -nO; o < nO; ++o) {
9931     const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o);
9932 
9933     for (c = 0; c < cS; ++c) if (sourceCone[arr[c*2]] != targetCone[c]) break;
9934     if (c == cS) {*ornt = o; break;}
9935   }
9936   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
9937   PetscFunctionReturn(0);
9938 }
9939 
9940 /*@C
9941   DMPolytopeGetOrientation - Determine an orientation that takes the source face arrangement to the target face arrangement
9942 
9943   Not collective
9944 
9945   Input Parameters:
9946 + ct         - The DMPolytopeType
9947 . sourceCone - The source arrangement of faces
9948 - targetCone - The target arrangement of faces
9949 
9950   Output Parameters:
9951 . ornt  - The orientation which will take the source arrangement to the target arrangement
9952 
9953   Note: This function will fail if no suitable orientation can be found.
9954 
9955   Level: advanced
9956 
9957 .seealso: `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`
9958 @*/
9959 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
9960 {
9961   PetscBool      found;
9962 
9963   PetscFunctionBegin;
9964   PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found));
9965   PetscCheck(found,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
9966   PetscFunctionReturn(0);
9967 }
9968 
9969 /*@C
9970   DMPolytopeMatchVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement
9971 
9972   Not collective
9973 
9974   Input Parameters:
9975 + ct         - The DMPolytopeType
9976 . sourceVert - The source arrangement of vertices
9977 - targetVert - The target arrangement of vertices
9978 
9979   Output Parameters:
9980 + ornt  - The orientation which will take the source arrangement to the target arrangement
9981 - found - Flag indicating that a suitable orientation was found
9982 
9983   Level: advanced
9984 
9985 .seealso: `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`
9986 @*/
9987 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found)
9988 {
9989   const PetscInt cS = DMPolytopeTypeGetNumVertices(ct);
9990   const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct)/2;
9991   PetscInt       o, c;
9992 
9993   PetscFunctionBegin;
9994   if (!nO) {*ornt = 0; *found = PETSC_TRUE; PetscFunctionReturn(0);}
9995   for (o = -nO; o < nO; ++o) {
9996     const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o);
9997 
9998     for (c = 0; c < cS; ++c) if (sourceVert[arr[c]] != targetVert[c]) break;
9999     if (c == cS) {*ornt = o; break;}
10000   }
10001   *found = o == nO ? PETSC_FALSE : PETSC_TRUE;
10002   PetscFunctionReturn(0);
10003 }
10004 
10005 /*@C
10006   DMPolytopeGetVertexOrientation - Determine an orientation that takes the source vertex arrangement to the target vertex arrangement
10007 
10008   Not collective
10009 
10010   Input Parameters:
10011 + ct         - The DMPolytopeType
10012 . sourceCone - The source arrangement of vertices
10013 - targetCone - The target arrangement of vertices
10014 
10015   Output Parameters:
10016 . ornt  - The orientation which will take the source arrangement to the target arrangement
10017 
10018   Note: This function will fail if no suitable orientation can be found.
10019 
10020   Level: advanced
10021 
10022 .seealso: `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()`
10023 @*/
10024 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt)
10025 {
10026   PetscBool      found;
10027 
10028   PetscFunctionBegin;
10029   PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found));
10030   PetscCheck(found,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]);
10031   PetscFunctionReturn(0);
10032 }
10033 
10034 /*@C
10035   DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type
10036 
10037   Not collective
10038 
10039   Input Parameters:
10040 + ct    - The DMPolytopeType
10041 - point - Coordinates of the point
10042 
10043   Output Parameters:
10044 . inside  - Flag indicating whether the point is inside the reference cell of given type
10045 
10046   Level: advanced
10047 
10048 .seealso: `DMLocatePoints()`
10049 @*/
10050 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside)
10051 {
10052   PetscReal sum = 0.0;
10053   PetscInt  d;
10054 
10055   PetscFunctionBegin;
10056   *inside = PETSC_TRUE;
10057   switch (ct) {
10058   case DM_POLYTOPE_TRIANGLE:
10059   case DM_POLYTOPE_TETRAHEDRON:
10060     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) {
10061       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
10062       sum += point[d];
10063     }
10064     if (sum > PETSC_SMALL) {*inside = PETSC_FALSE; break;}
10065     break;
10066   case DM_POLYTOPE_QUADRILATERAL:
10067   case DM_POLYTOPE_HEXAHEDRON:
10068     for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d)
10069       if (PetscAbsReal(point[d]) > 1.+PETSC_SMALL) {*inside = PETSC_FALSE; break;}
10070     break;
10071   default:
10072     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]);
10073   }
10074   PetscFunctionReturn(0);
10075 }
10076