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