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