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