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