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