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