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