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