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