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