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