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