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