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