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