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