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