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