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