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