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