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