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