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