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