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