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