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