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