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