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