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