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