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