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