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