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