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