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