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