xref: /petsc/src/dm/interface/dm.c (revision 95a2cb335deee435f0b06953e4461b2237b5f64e)
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   PetscErrorCode ierr;
4497 
4498   PetscFunctionBegin;
4499   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4500   ierr = PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection);CHKERRQ(ierr);
4501   PetscFunctionReturn(0);
4502 }
4503 
4504 /*@
4505   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
4506 
4507   Input Parameter:
4508 . dm - The DM
4509 
4510   Output Parameter:
4511 . sf - The PetscSF
4512 
4513   Level: intermediate
4514 
4515   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
4516 
4517 .seealso: DMSetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4518 @*/
4519 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
4520 {
4521   PetscFunctionBegin;
4522   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4523   PetscValidPointer(sf, 2);
4524   *sf = dm->sf;
4525   PetscFunctionReturn(0);
4526 }
4527 
4528 /*@
4529   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
4530 
4531   Input Parameters:
4532 + dm - The DM
4533 - sf - The PetscSF
4534 
4535   Level: intermediate
4536 
4537 .seealso: DMGetPointSF(), DMGetSectionSF(), DMSetSectionSF(), DMCreateSectionSF()
4538 @*/
4539 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
4540 {
4541   PetscErrorCode ierr;
4542 
4543   PetscFunctionBegin;
4544   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4545   if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
4546   ierr = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
4547   ierr = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
4548   dm->sf = sf;
4549   PetscFunctionReturn(0);
4550 }
4551 
4552 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc)
4553 {
4554   PetscClassId   id;
4555   PetscErrorCode ierr;
4556 
4557   PetscFunctionBegin;
4558   ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
4559   if (id == PETSCFE_CLASSID) {
4560     ierr = DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);CHKERRQ(ierr);
4561   } else if (id == PETSCFV_CLASSID) {
4562     ierr = DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE);CHKERRQ(ierr);
4563   } else {
4564     ierr = DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE);CHKERRQ(ierr);
4565   }
4566   PetscFunctionReturn(0);
4567 }
4568 
4569 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew)
4570 {
4571   RegionField   *tmpr;
4572   PetscInt       Nf = dm->Nf, f;
4573   PetscErrorCode ierr;
4574 
4575   PetscFunctionBegin;
4576   if (Nf >= NfNew) PetscFunctionReturn(0);
4577   ierr = PetscMalloc1(NfNew, &tmpr);CHKERRQ(ierr);
4578   for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f];
4579   for (f = Nf; f < NfNew; ++f) {tmpr[f].disc = NULL; tmpr[f].label = NULL; tmpr[f].avoidTensor = PETSC_FALSE;}
4580   ierr = PetscFree(dm->fields);CHKERRQ(ierr);
4581   dm->Nf     = NfNew;
4582   dm->fields = tmpr;
4583   PetscFunctionReturn(0);
4584 }
4585 
4586 /*@
4587   DMClearFields - Remove all fields from the DM
4588 
4589   Logically collective on dm
4590 
4591   Input Parameter:
4592 . dm - The DM
4593 
4594   Level: intermediate
4595 
4596 .seealso: DMGetNumFields(), DMSetNumFields(), DMSetField()
4597 @*/
4598 PetscErrorCode DMClearFields(DM dm)
4599 {
4600   PetscInt       f;
4601   PetscErrorCode ierr;
4602 
4603   PetscFunctionBegin;
4604   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4605   for (f = 0; f < dm->Nf; ++f) {
4606     ierr = PetscObjectDestroy(&dm->fields[f].disc);CHKERRQ(ierr);
4607     ierr = DMLabelDestroy(&dm->fields[f].label);CHKERRQ(ierr);
4608   }
4609   ierr = PetscFree(dm->fields);CHKERRQ(ierr);
4610   dm->fields = NULL;
4611   dm->Nf     = 0;
4612   PetscFunctionReturn(0);
4613 }
4614 
4615 /*@
4616   DMGetNumFields - Get the number of fields in the DM
4617 
4618   Not collective
4619 
4620   Input Parameter:
4621 . dm - The DM
4622 
4623   Output Parameter:
4624 . Nf - The number of fields
4625 
4626   Level: intermediate
4627 
4628 .seealso: DMSetNumFields(), DMSetField()
4629 @*/
4630 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
4631 {
4632   PetscFunctionBegin;
4633   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4634   PetscValidIntPointer(numFields, 2);
4635   *numFields = dm->Nf;
4636   PetscFunctionReturn(0);
4637 }
4638 
4639 /*@
4640   DMSetNumFields - Set the number of fields in the DM
4641 
4642   Logically collective on dm
4643 
4644   Input Parameters:
4645 + dm - The DM
4646 - Nf - The number of fields
4647 
4648   Level: intermediate
4649 
4650 .seealso: DMGetNumFields(), DMSetField()
4651 @*/
4652 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
4653 {
4654   PetscInt       Nf, f;
4655   PetscErrorCode ierr;
4656 
4657   PetscFunctionBegin;
4658   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4659   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4660   for (f = Nf; f < numFields; ++f) {
4661     PetscContainer obj;
4662 
4663     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
4664     ierr = DMAddField(dm, NULL, (PetscObject) obj);CHKERRQ(ierr);
4665     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
4666   }
4667   PetscFunctionReturn(0);
4668 }
4669 
4670 /*@
4671   DMGetField - Return the discretization object for a given DM field
4672 
4673   Not collective
4674 
4675   Input Parameters:
4676 + dm - The DM
4677 - f  - The field number
4678 
4679   Output Parameters:
4680 + label - The label indicating the support of the field, or NULL for the entire mesh
4681 - field - The discretization object
4682 
4683   Level: intermediate
4684 
4685 .seealso: DMAddField(), DMSetField()
4686 @*/
4687 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *field)
4688 {
4689   PetscFunctionBegin;
4690   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4691   PetscValidPointer(field, 3);
4692   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);
4693   if (label) *label = dm->fields[f].label;
4694   if (field) *field = dm->fields[f].disc;
4695   PetscFunctionReturn(0);
4696 }
4697 
4698 /* Does not clear the DS */
4699 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject field)
4700 {
4701   PetscErrorCode ierr;
4702 
4703   PetscFunctionBegin;
4704   ierr = DMFieldEnlarge_Static(dm, f+1);CHKERRQ(ierr);
4705   ierr = DMLabelDestroy(&dm->fields[f].label);CHKERRQ(ierr);
4706   ierr = PetscObjectDestroy(&dm->fields[f].disc);CHKERRQ(ierr);
4707   dm->fields[f].label = label;
4708   dm->fields[f].disc  = field;
4709   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4710   ierr = PetscObjectReference((PetscObject) field);CHKERRQ(ierr);
4711   PetscFunctionReturn(0);
4712 }
4713 
4714 /*@
4715   DMSetField - Set the discretization object for a given DM field
4716 
4717   Logically collective on dm
4718 
4719   Input Parameters:
4720 + dm    - The DM
4721 . f     - The field number
4722 . label - The label indicating the support of the field, or NULL for the entire mesh
4723 - field - The discretization object
4724 
4725   Level: intermediate
4726 
4727 .seealso: DMAddField(), DMGetField()
4728 @*/
4729 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject field)
4730 {
4731   PetscErrorCode ierr;
4732 
4733   PetscFunctionBegin;
4734   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4735   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4736   PetscValidHeader(field, 4);
4737   if (f < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be non-negative", f);
4738   ierr = DMSetField_Internal(dm, f, label, field);CHKERRQ(ierr);
4739   ierr = DMSetDefaultAdjacency_Private(dm, f, field);CHKERRQ(ierr);
4740   ierr = DMClearDS(dm);CHKERRQ(ierr);
4741   PetscFunctionReturn(0);
4742 }
4743 
4744 /*@
4745   DMAddField - Add the discretization object for the given DM field
4746 
4747   Logically collective on dm
4748 
4749   Input Parameters:
4750 + dm    - The DM
4751 . label - The label indicating the support of the field, or NULL for the entire mesh
4752 - field - The discretization object
4753 
4754   Level: intermediate
4755 
4756 .seealso: DMSetField(), DMGetField()
4757 @*/
4758 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject field)
4759 {
4760   PetscInt       Nf = dm->Nf;
4761   PetscErrorCode ierr;
4762 
4763   PetscFunctionBegin;
4764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4765   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);
4766   PetscValidHeader(field, 3);
4767   ierr = DMFieldEnlarge_Static(dm, Nf+1);CHKERRQ(ierr);
4768   dm->fields[Nf].label = label;
4769   dm->fields[Nf].disc  = field;
4770   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
4771   ierr = PetscObjectReference((PetscObject) field);CHKERRQ(ierr);
4772   ierr = DMSetDefaultAdjacency_Private(dm, Nf, field);CHKERRQ(ierr);
4773   ierr = DMClearDS(dm);CHKERRQ(ierr);
4774   PetscFunctionReturn(0);
4775 }
4776 
4777 /*@
4778   DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells
4779 
4780   Logically collective on dm
4781 
4782   Input Parameters:
4783 + dm          - The DM
4784 . f           - The field index
4785 - avoidTensor - The flag to avoid defining the field on tensor cells
4786 
4787   Level: intermediate
4788 
4789 .seealso: DMGetFieldAvoidTensor(), DMSetField(), DMGetField()
4790 @*/
4791 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor)
4792 {
4793   PetscFunctionBegin;
4794   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4795   dm->fields[f].avoidTensor = avoidTensor;
4796   PetscFunctionReturn(0);
4797 }
4798 
4799 /*@
4800   DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells
4801 
4802   Logically collective on dm
4803 
4804   Input Parameters:
4805 + dm          - The DM
4806 - f           - The field index
4807 
4808   Output Parameter:
4809 . avoidTensor - The flag to avoid defining the field on tensor cells
4810 
4811   Level: intermediate
4812 
4813 .seealso: DMSetFieldAvoidTensor(), DMSetField(), DMGetField()
4814 @*/
4815 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor)
4816 {
4817   PetscFunctionBegin;
4818   if ((f < 0) || (f >= dm->Nf)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Field %D is not in [0, %D)", f, dm->Nf);
4819   *avoidTensor = dm->fields[f].avoidTensor;
4820   PetscFunctionReturn(0);
4821 }
4822 
4823 /*@
4824   DMCopyFields - Copy the discretizations for the DM into another DM
4825 
4826   Collective on dm
4827 
4828   Input Parameter:
4829 . dm - The DM
4830 
4831   Output Parameter:
4832 . newdm - The DM
4833 
4834   Level: advanced
4835 
4836 .seealso: DMGetField(), DMSetField(), DMAddField(), DMCopyDS(), DMGetDS(), DMGetCellDS()
4837 @*/
4838 PetscErrorCode DMCopyFields(DM dm, DM newdm)
4839 {
4840   PetscInt       Nf, f;
4841   PetscErrorCode ierr;
4842 
4843   PetscFunctionBegin;
4844   if (dm == newdm) PetscFunctionReturn(0);
4845   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4846   ierr = DMClearFields(newdm);CHKERRQ(ierr);
4847   for (f = 0; f < Nf; ++f) {
4848     DMLabel     label;
4849     PetscObject field;
4850     PetscBool   useCone, useClosure;
4851 
4852     ierr = DMGetField(dm, f, &label, &field);CHKERRQ(ierr);
4853     ierr = DMSetField(newdm, f, label, field);CHKERRQ(ierr);
4854     ierr = DMGetAdjacency(dm, f, &useCone, &useClosure);CHKERRQ(ierr);
4855     ierr = DMSetAdjacency(newdm, f, useCone, useClosure);CHKERRQ(ierr);
4856   }
4857   PetscFunctionReturn(0);
4858 }
4859 
4860 /*@
4861   DMGetAdjacency - Returns the flags for determining variable influence
4862 
4863   Not collective
4864 
4865   Input Parameters:
4866 + dm - The DM object
4867 - f  - The field number, or PETSC_DEFAULT for the default adjacency
4868 
4869   Output Parameter:
4870 + useCone    - Flag for variable influence starting with the cone operation
4871 - useClosure - Flag for variable influence using transitive closure
4872 
4873   Notes:
4874 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4875 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4876 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4877   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4878 
4879   Level: developer
4880 
4881 .seealso: DMSetAdjacency(), DMGetField(), DMSetField()
4882 @*/
4883 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure)
4884 {
4885   PetscFunctionBegin;
4886   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4887   if (useCone)    PetscValidBoolPointer(useCone, 3);
4888   if (useClosure) PetscValidBoolPointer(useClosure, 4);
4889   if (f < 0) {
4890     if (useCone)    *useCone    = dm->adjacency[0];
4891     if (useClosure) *useClosure = dm->adjacency[1];
4892   } else {
4893     PetscInt       Nf;
4894     PetscErrorCode ierr;
4895 
4896     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4897     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4898     if (useCone)    *useCone    = dm->fields[f].adjacency[0];
4899     if (useClosure) *useClosure = dm->fields[f].adjacency[1];
4900   }
4901   PetscFunctionReturn(0);
4902 }
4903 
4904 /*@
4905   DMSetAdjacency - Set the flags for determining variable influence
4906 
4907   Not collective
4908 
4909   Input Parameters:
4910 + dm         - The DM object
4911 . f          - The field number
4912 . useCone    - Flag for variable influence starting with the cone operation
4913 - useClosure - Flag for variable influence using transitive closure
4914 
4915   Notes:
4916 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4917 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4918 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4919   Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another.
4920 
4921   Level: developer
4922 
4923 .seealso: DMGetAdjacency(), DMGetField(), DMSetField()
4924 @*/
4925 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure)
4926 {
4927   PetscFunctionBegin;
4928   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4929   if (f < 0) {
4930     dm->adjacency[0] = useCone;
4931     dm->adjacency[1] = useClosure;
4932   } else {
4933     PetscInt       Nf;
4934     PetscErrorCode ierr;
4935 
4936     ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4937     if (f >= Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %d must be in [0, %d)", f, Nf);
4938     dm->fields[f].adjacency[0] = useCone;
4939     dm->fields[f].adjacency[1] = useClosure;
4940   }
4941   PetscFunctionReturn(0);
4942 }
4943 
4944 /*@
4945   DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined
4946 
4947   Not collective
4948 
4949   Input Parameters:
4950 . dm - The DM object
4951 
4952   Output Parameter:
4953 + useCone    - Flag for variable influence starting with the cone operation
4954 - useClosure - Flag for variable influence using transitive closure
4955 
4956   Notes:
4957 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4958 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4959 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4960 
4961   Level: developer
4962 
4963 .seealso: DMSetBasicAdjacency(), DMGetField(), DMSetField()
4964 @*/
4965 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure)
4966 {
4967   PetscInt       Nf;
4968   PetscErrorCode ierr;
4969 
4970   PetscFunctionBegin;
4971   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4972   if (useCone)    PetscValidBoolPointer(useCone, 3);
4973   if (useClosure) PetscValidBoolPointer(useClosure, 4);
4974   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
4975   if (!Nf) {
4976     ierr = DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);CHKERRQ(ierr);
4977   } else {
4978     ierr = DMGetAdjacency(dm, 0, useCone, useClosure);CHKERRQ(ierr);
4979   }
4980   PetscFunctionReturn(0);
4981 }
4982 
4983 /*@
4984   DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined
4985 
4986   Not collective
4987 
4988   Input Parameters:
4989 + dm         - The DM object
4990 . useCone    - Flag for variable influence starting with the cone operation
4991 - useClosure - Flag for variable influence using transitive closure
4992 
4993   Notes:
4994 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)),   useCone = PETSC_FALSE, useClosure = PETSC_TRUE
4995 $     FVM:   Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
4996 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)),   useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
4997 
4998   Level: developer
4999 
5000 .seealso: DMGetBasicAdjacency(), DMGetField(), DMSetField()
5001 @*/
5002 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure)
5003 {
5004   PetscInt       Nf;
5005   PetscErrorCode ierr;
5006 
5007   PetscFunctionBegin;
5008   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5009   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
5010   if (!Nf) {
5011     ierr = DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure);CHKERRQ(ierr);
5012   } else {
5013     ierr = DMSetAdjacency(dm, 0, useCone, useClosure);CHKERRQ(ierr);
5014   }
5015   PetscFunctionReturn(0);
5016 }
5017 
5018 /* Complete labels that are being used for FEM BC */
5019 static PetscErrorCode DMCompleteBoundaryLabel_Internal(DM dm, PetscDS ds, PetscInt field, PetscInt bdNum, const char labelname[])
5020 {
5021   DMLabel        label;
5022   PetscObject    obj;
5023   PetscClassId   id;
5024   PetscInt       Nbd, bd;
5025   PetscBool      isFE      = PETSC_FALSE;
5026   PetscBool      duplicate = PETSC_FALSE;
5027   PetscErrorCode ierr;
5028 
5029   PetscFunctionBegin;
5030   ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr);
5031   ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr);
5032   if (id == PETSCFE_CLASSID) isFE = PETSC_TRUE;
5033   ierr = DMGetLabel(dm, labelname, &label);CHKERRQ(ierr);
5034   if (isFE && label) {
5035     /* Only want to modify label once */
5036     ierr = PetscDSGetNumBoundary(ds, &Nbd);CHKERRQ(ierr);
5037     for (bd = 0; bd < PetscMin(Nbd, bdNum); ++bd) {
5038       const char *lname;
5039 
5040       ierr = PetscDSGetBoundary(ds, bd, NULL, NULL, &lname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5041       ierr = PetscStrcmp(lname, labelname, &duplicate);CHKERRQ(ierr);
5042       if (duplicate) break;
5043     }
5044     if (!duplicate) {
5045       DM plex;
5046 
5047       ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
5048       if (plex) {ierr = DMPlexLabelComplete(plex, label);CHKERRQ(ierr);}
5049       ierr = DMDestroy(&plex);CHKERRQ(ierr);
5050     }
5051   }
5052   PetscFunctionReturn(0);
5053 }
5054 
5055 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew)
5056 {
5057   DMSpace       *tmpd;
5058   PetscInt       Nds = dm->Nds, s;
5059   PetscErrorCode ierr;
5060 
5061   PetscFunctionBegin;
5062   if (Nds >= NdsNew) PetscFunctionReturn(0);
5063   ierr = PetscMalloc1(NdsNew, &tmpd);CHKERRQ(ierr);
5064   for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s];
5065   for (s = Nds; s < NdsNew; ++s) {tmpd[s].ds = NULL; tmpd[s].label = NULL; tmpd[s].fields = NULL;}
5066   ierr = PetscFree(dm->probs);CHKERRQ(ierr);
5067   dm->Nds   = NdsNew;
5068   dm->probs = tmpd;
5069   PetscFunctionReturn(0);
5070 }
5071 
5072 /*@
5073   DMGetNumDS - Get the number of discrete systems in the DM
5074 
5075   Not collective
5076 
5077   Input Parameter:
5078 . dm - The DM
5079 
5080   Output Parameter:
5081 . Nds - The number of PetscDS objects
5082 
5083   Level: intermediate
5084 
5085 .seealso: DMGetDS(), DMGetCellDS()
5086 @*/
5087 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds)
5088 {
5089   PetscFunctionBegin;
5090   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5091   PetscValidIntPointer(Nds, 2);
5092   *Nds = dm->Nds;
5093   PetscFunctionReturn(0);
5094 }
5095 
5096 /*@
5097   DMClearDS - Remove all discrete systems from the DM
5098 
5099   Logically collective on dm
5100 
5101   Input Parameter:
5102 . dm - The DM
5103 
5104   Level: intermediate
5105 
5106 .seealso: DMGetNumDS(), DMGetDS(), DMSetField()
5107 @*/
5108 PetscErrorCode DMClearDS(DM dm)
5109 {
5110   PetscInt       s;
5111   PetscErrorCode ierr;
5112 
5113   PetscFunctionBegin;
5114   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5115   for (s = 0; s < dm->Nds; ++s) {
5116     ierr = PetscDSDestroy(&dm->probs[s].ds);CHKERRQ(ierr);
5117     ierr = DMLabelDestroy(&dm->probs[s].label);CHKERRQ(ierr);
5118     ierr = ISDestroy(&dm->probs[s].fields);CHKERRQ(ierr);
5119   }
5120   ierr = PetscFree(dm->probs);CHKERRQ(ierr);
5121   dm->probs = NULL;
5122   dm->Nds   = 0;
5123   PetscFunctionReturn(0);
5124 }
5125 
5126 /*@
5127   DMGetDS - Get the default PetscDS
5128 
5129   Not collective
5130 
5131   Input Parameter:
5132 . dm    - The DM
5133 
5134   Output Parameter:
5135 . prob - The default PetscDS
5136 
5137   Level: intermediate
5138 
5139 .seealso: DMGetCellDS(), DMGetRegionDS()
5140 @*/
5141 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
5142 {
5143   PetscErrorCode ierr;
5144 
5145   PetscFunctionBeginHot;
5146   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5147   PetscValidPointer(prob, 2);
5148   if (dm->Nds <= 0) {
5149     PetscDS ds;
5150 
5151     ierr = PetscDSCreate(PetscObjectComm((PetscObject) dm), &ds);CHKERRQ(ierr);
5152     ierr = DMSetRegionDS(dm, NULL, NULL, ds);CHKERRQ(ierr);
5153     ierr = PetscDSDestroy(&ds);CHKERRQ(ierr);
5154   }
5155   *prob = dm->probs[0].ds;
5156   PetscFunctionReturn(0);
5157 }
5158 
5159 /*@
5160   DMGetCellDS - Get the PetscDS defined on a given cell
5161 
5162   Not collective
5163 
5164   Input Parameters:
5165 + dm    - The DM
5166 - point - Cell for the DS
5167 
5168   Output Parameter:
5169 . prob - The PetscDS defined on the given cell
5170 
5171   Level: developer
5172 
5173 .seealso: DMGetDS(), DMSetRegionDS()
5174 @*/
5175 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *prob)
5176 {
5177   PetscDS        probDef = NULL;
5178   PetscInt       s;
5179   PetscErrorCode ierr;
5180 
5181   PetscFunctionBeginHot;
5182   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5183   PetscValidPointer(prob, 3);
5184   if (point < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %D", point);
5185   *prob = NULL;
5186   for (s = 0; s < dm->Nds; ++s) {
5187     PetscInt val;
5188 
5189     if (!dm->probs[s].label) {probDef = dm->probs[s].ds;}
5190     else {
5191       ierr = DMLabelGetValue(dm->probs[s].label, point, &val);CHKERRQ(ierr);
5192       if (val >= 0) {*prob = dm->probs[s].ds; break;}
5193     }
5194   }
5195   if (!*prob) *prob = probDef;
5196   PetscFunctionReturn(0);
5197 }
5198 
5199 /*@
5200   DMGetRegionDS - Get the PetscDS for a given mesh region, defined by a DMLabel
5201 
5202   Not collective
5203 
5204   Input Parameters:
5205 + dm    - The DM
5206 - label - The DMLabel defining the mesh region, or NULL for the entire mesh
5207 
5208   Output Parameters:
5209 + fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5210 - prob - The PetscDS defined on the given region, or NULL
5211 
5212   Note: If the label is missing, this function returns an error
5213 
5214   Level: advanced
5215 
5216 .seealso: DMGetRegionNumDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5217 @*/
5218 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds)
5219 {
5220   PetscInt Nds = dm->Nds, s;
5221 
5222   PetscFunctionBegin;
5223   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5224   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5225   if (fields) {PetscValidPointer(fields, 3); *fields = NULL;}
5226   if (ds)     {PetscValidPointer(ds, 4);     *ds     = NULL;}
5227   for (s = 0; s < Nds; ++s) {
5228     if (dm->probs[s].label == label) {
5229       if (fields) *fields = dm->probs[s].fields;
5230       if (ds)     *ds     = dm->probs[s].ds;
5231       PetscFunctionReturn(0);
5232     }
5233   }
5234   PetscFunctionReturn(0);
5235 }
5236 
5237 /*@
5238   DMSetRegionDS - Set the PetscDS for a given mesh region, defined by a DMLabel
5239 
5240   Collective on dm
5241 
5242   Input Parameters:
5243 + dm     - The DM
5244 . label  - The DMLabel defining the mesh region, or NULL for the entire mesh
5245 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL for all fields
5246 - prob   - The PetscDS defined on the given cell
5247 
5248   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM. If DS is replaced,
5249   the fields argument is ignored.
5250 
5251   Level: advanced
5252 
5253 .seealso: DMGetRegionDS(), DMSetRegionNumDS(), DMGetDS(), DMGetCellDS()
5254 @*/
5255 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds)
5256 {
5257   PetscInt       Nds = dm->Nds, s;
5258   PetscErrorCode ierr;
5259 
5260   PetscFunctionBegin;
5261   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5262   if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2);
5263   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 3);
5264   for (s = 0; s < Nds; ++s) {
5265     if (dm->probs[s].label == label) {
5266       ierr = PetscDSDestroy(&dm->probs[s].ds);CHKERRQ(ierr);
5267       dm->probs[s].ds = ds;
5268       PetscFunctionReturn(0);
5269     }
5270   }
5271   ierr = DMDSEnlarge_Static(dm, Nds+1);CHKERRQ(ierr);
5272   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
5273   ierr = PetscObjectReference((PetscObject) fields);CHKERRQ(ierr);
5274   ierr = PetscObjectReference((PetscObject) ds);CHKERRQ(ierr);
5275   if (!label) {
5276     /* Put the NULL label at the front, so it is returned as the default */
5277     for (s = Nds-1; s >=0; --s) dm->probs[s+1] = dm->probs[s];
5278     Nds = 0;
5279   }
5280   dm->probs[Nds].label  = label;
5281   dm->probs[Nds].fields = fields;
5282   dm->probs[Nds].ds     = ds;
5283   PetscFunctionReturn(0);
5284 }
5285 
5286 /*@
5287   DMGetRegionNumDS - Get the PetscDS for a given mesh region, defined by the region number
5288 
5289   Not collective
5290 
5291   Input Parameters:
5292 + dm  - The DM
5293 - num - The region number, in [0, Nds)
5294 
5295   Output Parameters:
5296 + label  - The region label, or NULL
5297 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL
5298 - ds     - The PetscDS defined on the given region, or NULL
5299 
5300   Level: advanced
5301 
5302 .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5303 @*/
5304 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds)
5305 {
5306   PetscInt       Nds;
5307   PetscErrorCode ierr;
5308 
5309   PetscFunctionBegin;
5310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5311   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5312   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5313   if (label) {
5314     PetscValidPointer(label, 3);
5315     *label = dm->probs[num].label;
5316   }
5317   if (fields) {
5318     PetscValidPointer(fields, 4);
5319     *fields = dm->probs[num].fields;
5320   }
5321   if (ds) {
5322     PetscValidPointer(ds, 5);
5323     *ds = dm->probs[num].ds;
5324   }
5325   PetscFunctionReturn(0);
5326 }
5327 
5328 /*@
5329   DMSetRegionNumDS - Set the PetscDS for a given mesh region, defined by the region number
5330 
5331   Not collective
5332 
5333   Input Parameters:
5334 + dm     - The DM
5335 . num    - The region number, in [0, Nds)
5336 . label  - The region label, or NULL
5337 . fields - The IS containing the DM field numbers for the fields in this DS, or NULL to prevent setting
5338 - ds     - The PetscDS defined on the given region, or NULL to prevent setting
5339 
5340   Level: advanced
5341 
5342 .seealso: DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5343 @*/
5344 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds)
5345 {
5346   PetscInt       Nds;
5347   PetscErrorCode ierr;
5348 
5349   PetscFunctionBegin;
5350   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5351   if (label) {PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3);}
5352   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5353   if ((num < 0) || (num >= Nds)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %D is not in [0, %D)", num, Nds);
5354   ierr = PetscObjectReference((PetscObject) label);CHKERRQ(ierr);
5355   ierr = DMLabelDestroy(&dm->probs[num].label);CHKERRQ(ierr);
5356   dm->probs[num].label = label;
5357   if (fields) {
5358     PetscValidHeaderSpecific(fields, IS_CLASSID, 4);
5359     ierr = PetscObjectReference((PetscObject) fields);CHKERRQ(ierr);
5360     ierr = ISDestroy(&dm->probs[num].fields);CHKERRQ(ierr);
5361     dm->probs[num].fields = fields;
5362   }
5363   if (ds) {
5364     PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5);
5365     ierr = PetscObjectReference((PetscObject) ds);CHKERRQ(ierr);
5366     ierr = PetscDSDestroy(&dm->probs[num].ds);CHKERRQ(ierr);
5367     dm->probs[num].ds = ds;
5368   }
5369   PetscFunctionReturn(0);
5370 }
5371 
5372 /*@
5373   DMFindRegionNum - Find the region number for a given PetscDS, or -1 if it is not found.
5374 
5375   Not collective
5376 
5377   Input Parameters:
5378 + dm  - The DM
5379 - ds  - The PetscDS defined on the given region
5380 
5381   Output Parameter:
5382 . num - The region number, in [0, Nds), or -1 if not found
5383 
5384   Level: advanced
5385 
5386 .seealso: DMGetRegionNumDS(), DMGetRegionDS(), DMSetRegionDS(), DMGetDS(), DMGetCellDS()
5387 @*/
5388 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num)
5389 {
5390   PetscInt       Nds, n;
5391   PetscErrorCode ierr;
5392 
5393   PetscFunctionBegin;
5394   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5395   PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2);
5396   PetscValidPointer(num, 3);
5397   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5398   for (n = 0; n < Nds; ++n) if (ds == dm->probs[n].ds) break;
5399   if (n >= Nds) *num = -1;
5400   else          *num = n;
5401   PetscFunctionReturn(0);
5402 }
5403 
5404 /*@
5405   DMCreateDS - Create the discrete systems for the DM based upon the fields added to the DM
5406 
5407   Collective on dm
5408 
5409   Input Parameter:
5410 . dm - The DM
5411 
5412   Note: If the label has a DS defined, it will be replaced. Otherwise, it will be added to the DM.
5413 
5414   Level: intermediate
5415 
5416 .seealso: DMSetField, DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5417 @*/
5418 PetscErrorCode DMCreateDS(DM dm)
5419 {
5420   MPI_Comm       comm;
5421   PetscDS        dsDef;
5422   DMLabel       *labelSet;
5423   PetscInt       dE, Nf = dm->Nf, f, s, Nl, l, Ndef;
5424   PetscBool      doSetup = PETSC_TRUE;
5425   PetscErrorCode ierr;
5426 
5427   PetscFunctionBegin;
5428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5429   if (!dm->fields) PetscFunctionReturn(0);
5430   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
5431   ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
5432   /* Determine how many regions we have */
5433   ierr = PetscMalloc1(Nf, &labelSet);CHKERRQ(ierr);
5434   Nl   = 0;
5435   Ndef = 0;
5436   for (f = 0; f < Nf; ++f) {
5437     DMLabel  label = dm->fields[f].label;
5438     PetscInt l;
5439 
5440     if (!label) {++Ndef; continue;}
5441     for (l = 0; l < Nl; ++l) if (label == labelSet[l]) break;
5442     if (l < Nl) continue;
5443     labelSet[Nl++] = label;
5444   }
5445   /* Create default DS if there are no labels to intersect with */
5446   ierr = DMGetRegionDS(dm, NULL, NULL, &dsDef);CHKERRQ(ierr);
5447   if (!dsDef && Ndef && !Nl) {
5448     IS        fields;
5449     PetscInt *fld, nf;
5450 
5451     for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) ++nf;
5452     if (nf) {
5453       ierr = PetscMalloc1(nf, &fld);CHKERRQ(ierr);
5454       for (f = 0, nf = 0; f < Nf; ++f) if (!dm->fields[f].label) fld[nf++] = f;
5455       ierr = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
5456       ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
5457       ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
5458       ierr = ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
5459 
5460       ierr = PetscDSCreate(comm, &dsDef);CHKERRQ(ierr);
5461       ierr = DMSetRegionDS(dm, NULL, fields, dsDef);CHKERRQ(ierr);
5462       ierr = PetscDSDestroy(&dsDef);CHKERRQ(ierr);
5463       ierr = ISDestroy(&fields);CHKERRQ(ierr);
5464     }
5465   }
5466   ierr = DMGetRegionDS(dm, NULL, NULL, &dsDef);CHKERRQ(ierr);
5467   if (dsDef) {ierr = PetscDSSetCoordinateDimension(dsDef, dE);CHKERRQ(ierr);}
5468   /* Intersect labels with default fields */
5469   if (Ndef && Nl) {
5470     DM              plex;
5471     DMLabel         cellLabel;
5472     IS              fieldIS, allcellIS, defcellIS = NULL;
5473     PetscInt       *fields;
5474     const PetscInt *cells;
5475     PetscInt        depth, nf = 0, n, c;
5476 
5477     ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr);
5478     ierr = DMPlexGetDepth(plex, &depth);CHKERRQ(ierr);
5479     ierr = DMGetStratumIS(plex, "dim", depth, &allcellIS);CHKERRQ(ierr);
5480     if (!allcellIS) {ierr = DMGetStratumIS(plex, "depth", depth, &allcellIS);CHKERRQ(ierr);}
5481     for (l = 0; l < Nl; ++l) {
5482       DMLabel label = labelSet[l];
5483       IS      pointIS;
5484 
5485       ierr = ISDestroy(&defcellIS);CHKERRQ(ierr);
5486       ierr = DMLabelGetStratumIS(label, 1, &pointIS);CHKERRQ(ierr);
5487       ierr = ISDifference(allcellIS, pointIS, &defcellIS);CHKERRQ(ierr);
5488       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5489     }
5490     ierr = ISDestroy(&allcellIS);CHKERRQ(ierr);
5491 
5492     ierr = DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel);CHKERRQ(ierr);
5493     ierr = ISGetLocalSize(defcellIS, &n);CHKERRQ(ierr);
5494     ierr = ISGetIndices(defcellIS, &cells);CHKERRQ(ierr);
5495     for (c = 0; c < n; ++c) {ierr = DMLabelSetValue(cellLabel, cells[c], 1);CHKERRQ(ierr);}
5496     ierr = ISRestoreIndices(defcellIS, &cells);CHKERRQ(ierr);
5497     ierr = ISDestroy(&defcellIS);CHKERRQ(ierr);
5498     ierr = DMPlexLabelComplete(plex, cellLabel);CHKERRQ(ierr);
5499 
5500     ierr = PetscMalloc1(Ndef, &fields);CHKERRQ(ierr);
5501     for (f = 0; f < Nf; ++f) if (!dm->fields[f].label) fields[nf++] = f;
5502     ierr = ISCreate(PETSC_COMM_SELF, &fieldIS);CHKERRQ(ierr);
5503     ierr = PetscObjectSetOptionsPrefix((PetscObject) fieldIS, "dm_fields_");CHKERRQ(ierr);
5504     ierr = ISSetType(fieldIS, ISGENERAL);CHKERRQ(ierr);
5505     ierr = ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER);CHKERRQ(ierr);
5506 
5507     ierr = PetscDSCreate(comm, &dsDef);CHKERRQ(ierr);
5508     ierr = DMSetRegionDS(dm, cellLabel, fieldIS, dsDef);CHKERRQ(ierr);
5509     ierr = DMLabelDestroy(&cellLabel);CHKERRQ(ierr);
5510     ierr = PetscDSSetCoordinateDimension(dsDef, dE);CHKERRQ(ierr);
5511     ierr = PetscDSDestroy(&dsDef);CHKERRQ(ierr);
5512     ierr = ISDestroy(&fieldIS);CHKERRQ(ierr);
5513     ierr = DMDestroy(&plex);CHKERRQ(ierr);
5514   }
5515   /* Create label DSes
5516      - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS
5517   */
5518   /* TODO Should check that labels are disjoint */
5519   for (l = 0; l < Nl; ++l) {
5520     DMLabel   label = labelSet[l];
5521     PetscDS   ds;
5522     IS        fields;
5523     PetscInt *fld, nf;
5524 
5525     ierr = PetscDSCreate(comm, &ds);CHKERRQ(ierr);
5526     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) ++nf;
5527     ierr = PetscMalloc1(nf, &fld);CHKERRQ(ierr);
5528     for (f = 0, nf = 0; f < Nf; ++f) if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f;
5529     ierr = ISCreate(PETSC_COMM_SELF, &fields);CHKERRQ(ierr);
5530     ierr = PetscObjectSetOptionsPrefix((PetscObject) fields, "dm_fields_");CHKERRQ(ierr);
5531     ierr = ISSetType(fields, ISGENERAL);CHKERRQ(ierr);
5532     ierr = ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER);CHKERRQ(ierr);
5533     ierr = DMSetRegionDS(dm, label, fields, ds);CHKERRQ(ierr);
5534     ierr = ISDestroy(&fields);CHKERRQ(ierr);
5535     ierr = PetscDSSetCoordinateDimension(ds, dE);CHKERRQ(ierr);
5536     {
5537       DMPolytopeType ct;
5538       PetscInt       lStart, lEnd;
5539       PetscBool      isHybridLocal = PETSC_FALSE, isHybrid;
5540 
5541       ierr = DMLabelGetBounds(label, &lStart, &lEnd);CHKERRQ(ierr);
5542       if (lStart >= 0) {
5543         ierr = DMPlexGetCellType(dm, lStart, &ct);CHKERRQ(ierr);
5544         switch (ct) {
5545           case DM_POLYTOPE_POINT_PRISM_TENSOR:
5546           case DM_POLYTOPE_SEG_PRISM_TENSOR:
5547           case DM_POLYTOPE_TRI_PRISM_TENSOR:
5548           case DM_POLYTOPE_QUAD_PRISM_TENSOR:
5549             isHybridLocal = PETSC_TRUE;break;
5550           default: break;
5551         }
5552       }
5553       ierr = MPI_Allreduce(&isHybridLocal, &isHybrid, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
5554       ierr = PetscDSSetHybrid(ds, isHybrid);CHKERRQ(ierr);
5555     }
5556     ierr = PetscDSDestroy(&ds);CHKERRQ(ierr);
5557   }
5558   ierr = PetscFree(labelSet);CHKERRQ(ierr);
5559   /* Set fields in DSes */
5560   for (s = 0; s < dm->Nds; ++s) {
5561     PetscDS         ds     = dm->probs[s].ds;
5562     IS              fields = dm->probs[s].fields;
5563     const PetscInt *fld;
5564     PetscInt        nf;
5565 
5566     ierr = ISGetLocalSize(fields, &nf);CHKERRQ(ierr);
5567     ierr = ISGetIndices(fields, &fld);CHKERRQ(ierr);
5568     for (f = 0; f < nf; ++f) {
5569       PetscObject  disc  = dm->fields[fld[f]].disc;
5570       PetscBool    isHybrid;
5571       PetscClassId id;
5572 
5573       ierr = PetscDSGetHybrid(ds, &isHybrid);CHKERRQ(ierr);
5574       /* If this is a cohesive cell, then it needs the lower dimensional discretization */
5575       if (isHybrid && f < nf-1) {ierr = PetscFEGetHeightSubspace((PetscFE) disc, 1, (PetscFE *) &disc);CHKERRQ(ierr);}
5576       ierr = PetscDSSetDiscretization(ds, f, disc);CHKERRQ(ierr);
5577       /* We allow people to have placeholder fields and construct the Section by hand */
5578       ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr);
5579       if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE;
5580     }
5581     ierr = ISRestoreIndices(fields, &fld);CHKERRQ(ierr);
5582   }
5583   /* Setup DSes */
5584   if (doSetup) {
5585     for (s = 0; s < dm->Nds; ++s) {ierr = PetscDSSetUp(dm->probs[s].ds);CHKERRQ(ierr);}
5586   }
5587   PetscFunctionReturn(0);
5588 }
5589 
5590 /*@
5591   DMComputeExactSolution - Compute the exact solution for a given DM, using the PetscDS information.
5592 
5593   Collective on DM
5594 
5595   Input Parameters:
5596 + dm   - The DM
5597 - time - The time
5598 
5599   Output Parameters:
5600 + u    - The vector will be filled with exact solution values, or NULL
5601 - u_t  - The vector will be filled with the time derivative of exact solution values, or NULL
5602 
5603   Note: The user must call PetscDSSetExactSolution() beforehand
5604 
5605   Level: developer
5606 
5607 .seealso: PetscDSSetExactSolution()
5608 @*/
5609 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t)
5610 {
5611   PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx);
5612   void            **ectxs;
5613   PetscInt          Nf, Nds, s;
5614   PetscErrorCode    ierr;
5615 
5616   PetscFunctionBegin;
5617   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5618   if (u)   PetscValidHeaderSpecific(u, VEC_CLASSID, 3);
5619   if (u_t) PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4);
5620   ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr);
5621   ierr = PetscMalloc2(Nf, &exacts, Nf, &ectxs);CHKERRQ(ierr);
5622   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5623   for (s = 0; s < Nds; ++s) {
5624     PetscDS         ds;
5625     DMLabel         label;
5626     IS              fieldIS;
5627     const PetscInt *fields, id = 1;
5628     PetscInt        dsNf, f;
5629 
5630     ierr = DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds);CHKERRQ(ierr);
5631     ierr = PetscDSGetNumFields(ds, &dsNf);CHKERRQ(ierr);
5632     ierr = ISGetIndices(fieldIS, &fields);CHKERRQ(ierr);
5633     ierr = PetscArrayzero(exacts, Nf);CHKERRQ(ierr);
5634     ierr = PetscArrayzero(ectxs, Nf);CHKERRQ(ierr);
5635     if (u) {
5636       for (f = 0; f < dsNf; ++f) {
5637         const PetscInt field = fields[f];
5638         ierr = PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field]);CHKERRQ(ierr);
5639       }
5640       ierr = ISRestoreIndices(fieldIS, &fields);CHKERRQ(ierr);
5641       if (label) {
5642         ierr = DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u);CHKERRQ(ierr);
5643       } else {
5644         ierr = DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u);CHKERRQ(ierr);
5645       }
5646     }
5647     if (u_t) {
5648       ierr = PetscArrayzero(exacts, Nf);CHKERRQ(ierr);
5649       ierr = PetscArrayzero(ectxs, Nf);CHKERRQ(ierr);
5650       for (f = 0; f < dsNf; ++f) {
5651         const PetscInt field = fields[f];
5652         ierr = PetscDSGetExactSolutionTimeDerivative(ds, field, &exacts[field], &ectxs[field]);CHKERRQ(ierr);
5653       }
5654       ierr = ISRestoreIndices(fieldIS, &fields);CHKERRQ(ierr);
5655       if (label) {
5656         ierr = DMProjectFunctionLabel(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, u_t);CHKERRQ(ierr);
5657       } else {
5658         ierr = DMProjectFunction(dm, time, exacts, ectxs, INSERT_ALL_VALUES, u_t);CHKERRQ(ierr);
5659       }
5660     }
5661   }
5662   if (u) {
5663     ierr = PetscObjectSetName((PetscObject) u, "Exact Solution");CHKERRQ(ierr);
5664     ierr = PetscObjectSetOptionsPrefix((PetscObject) u, "exact_");CHKERRQ(ierr);
5665   }
5666   if (u_t) {
5667     ierr = PetscObjectSetName((PetscObject) u, "Exact Solution Time Derivative");CHKERRQ(ierr);
5668     ierr = PetscObjectSetOptionsPrefix((PetscObject) u_t, "exact_t_");CHKERRQ(ierr);
5669   }
5670   ierr = PetscFree2(exacts, ectxs);CHKERRQ(ierr);
5671   PetscFunctionReturn(0);
5672 }
5673 
5674 /*@
5675   DMCopyDS - Copy the discrete systems for the DM into another DM
5676 
5677   Collective on dm
5678 
5679   Input Parameter:
5680 . dm - The DM
5681 
5682   Output Parameter:
5683 . newdm - The DM
5684 
5685   Level: advanced
5686 
5687 .seealso: DMCopyFields(), DMAddField(), DMGetDS(), DMGetCellDS(), DMGetRegionDS(), DMSetRegionDS()
5688 @*/
5689 PetscErrorCode DMCopyDS(DM dm, DM newdm)
5690 {
5691   PetscInt       Nds, s;
5692   PetscErrorCode ierr;
5693 
5694   PetscFunctionBegin;
5695   if (dm == newdm) PetscFunctionReturn(0);
5696   ierr = DMGetNumDS(dm, &Nds);CHKERRQ(ierr);
5697   ierr = DMClearDS(newdm);CHKERRQ(ierr);
5698   for (s = 0; s < Nds; ++s) {
5699     DMLabel  label;
5700     IS       fields;
5701     PetscDS  ds;
5702     PetscInt Nbd, bd;
5703 
5704     ierr = DMGetRegionNumDS(dm, s, &label, &fields, &ds);CHKERRQ(ierr);
5705     ierr = DMSetRegionDS(newdm, label, fields, ds);CHKERRQ(ierr);
5706     ierr = PetscDSGetNumBoundary(ds, &Nbd);CHKERRQ(ierr);
5707     for (bd = 0; bd < Nbd; ++bd) {
5708       const char *labelname, *name;
5709       PetscInt    field;
5710 
5711       /* Do not check if label exists here, since p4est calls this for the reference tree which does not have the labels */
5712       ierr = PetscDSGetBoundary(ds, bd, NULL, &name, &labelname, &field, NULL, NULL, NULL, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
5713       ierr = DMCompleteBoundaryLabel_Internal(newdm, ds, field, bd, labelname);CHKERRQ(ierr);
5714     }
5715   }
5716   PetscFunctionReturn(0);
5717 }
5718 
5719 /*@
5720   DMCopyDisc - Copy the fields and discrete systems for the DM into another DM
5721 
5722   Collective on dm
5723 
5724   Input Parameter:
5725 . dm - The DM
5726 
5727   Output Parameter:
5728 . newdm - The DM
5729 
5730   Level: advanced
5731 
5732 .seealso: DMCopyFields(), DMCopyDS()
5733 @*/
5734 PetscErrorCode DMCopyDisc(DM dm, DM newdm)
5735 {
5736   PetscErrorCode ierr;
5737 
5738   PetscFunctionBegin;
5739   ierr = DMCopyFields(dm, newdm);CHKERRQ(ierr);
5740   ierr = DMCopyDS(dm, newdm);CHKERRQ(ierr);
5741   PetscFunctionReturn(0);
5742 }
5743 
5744 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
5745 {
5746   DM dm_coord,dmc_coord;
5747   PetscErrorCode ierr;
5748   Vec coords,ccoords;
5749   Mat inject;
5750   PetscFunctionBegin;
5751   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5752   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
5753   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5754   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
5755   if (coords && !ccoords) {
5756     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
5757     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5758     ierr = DMCreateInjection(dmc_coord,dm_coord,&inject);CHKERRQ(ierr);
5759     ierr = MatRestrict(inject,coords,ccoords);CHKERRQ(ierr);
5760     ierr = MatDestroy(&inject);CHKERRQ(ierr);
5761     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
5762     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5763   }
5764   PetscFunctionReturn(0);
5765 }
5766 
5767 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
5768 {
5769   DM dm_coord,subdm_coord;
5770   PetscErrorCode ierr;
5771   Vec coords,ccoords,clcoords;
5772   VecScatter *scat_i,*scat_g;
5773   PetscFunctionBegin;
5774   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
5775   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
5776   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
5777   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
5778   if (coords && !ccoords) {
5779     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
5780     ierr = PetscObjectSetName((PetscObject)ccoords,"coordinates");CHKERRQ(ierr);
5781     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
5782     ierr = PetscObjectSetName((PetscObject)clcoords,"coordinates");CHKERRQ(ierr);
5783     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
5784     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5785     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5786     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5787     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5788     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
5789     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
5790     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
5791     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
5792     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
5793     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
5794     ierr = PetscFree(scat_i);CHKERRQ(ierr);
5795     ierr = PetscFree(scat_g);CHKERRQ(ierr);
5796   }
5797   PetscFunctionReturn(0);
5798 }
5799 
5800 /*@
5801   DMGetDimension - Return the topological dimension of the DM
5802 
5803   Not collective
5804 
5805   Input Parameter:
5806 . dm - The DM
5807 
5808   Output Parameter:
5809 . dim - The topological dimension
5810 
5811   Level: beginner
5812 
5813 .seealso: DMSetDimension(), DMCreate()
5814 @*/
5815 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
5816 {
5817   PetscFunctionBegin;
5818   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5819   PetscValidIntPointer(dim, 2);
5820   *dim = dm->dim;
5821   PetscFunctionReturn(0);
5822 }
5823 
5824 /*@
5825   DMSetDimension - Set the topological dimension of the DM
5826 
5827   Collective on dm
5828 
5829   Input Parameters:
5830 + dm - The DM
5831 - dim - The topological dimension
5832 
5833   Level: beginner
5834 
5835 .seealso: DMGetDimension(), DMCreate()
5836 @*/
5837 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
5838 {
5839   PetscDS        ds;
5840   PetscErrorCode ierr;
5841 
5842   PetscFunctionBegin;
5843   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5844   PetscValidLogicalCollectiveInt(dm, dim, 2);
5845   dm->dim = dim;
5846   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
5847   if (ds->dimEmbed < 0) {ierr = PetscDSSetCoordinateDimension(ds, dm->dim);CHKERRQ(ierr);}
5848   PetscFunctionReturn(0);
5849 }
5850 
5851 /*@
5852   DMGetDimPoints - Get the half-open interval for all points of a given dimension
5853 
5854   Collective on dm
5855 
5856   Input Parameters:
5857 + dm - the DM
5858 - dim - the dimension
5859 
5860   Output Parameters:
5861 + pStart - The first point of the given dimension
5862 - pEnd - The first point following points of the given dimension
5863 
5864   Note:
5865   The points are vertices in the Hasse diagram encoding the topology. This is explained in
5866   https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme,
5867   then the interval is empty.
5868 
5869   Level: intermediate
5870 
5871 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
5872 @*/
5873 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
5874 {
5875   PetscInt       d;
5876   PetscErrorCode ierr;
5877 
5878   PetscFunctionBegin;
5879   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5880   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
5881   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
5882   if (!dm->ops->getdimpoints) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "DM type %s does not implement DMGetDimPoints",((PetscObject)dm)->type_name);
5883   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
5884   PetscFunctionReturn(0);
5885 }
5886 
5887 /*@
5888   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
5889 
5890   Collective on dm
5891 
5892   Input Parameters:
5893 + dm - the DM
5894 - c - coordinate vector
5895 
5896   Notes:
5897   The coordinates do include those for ghost points, which are in the local vector.
5898 
5899   The vector c should be destroyed by the caller.
5900 
5901   Level: intermediate
5902 
5903 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5904 @*/
5905 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
5906 {
5907   PetscErrorCode ierr;
5908 
5909   PetscFunctionBegin;
5910   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5911   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5912   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5913   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5914   dm->coordinates = c;
5915   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5916   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5917   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
5918   PetscFunctionReturn(0);
5919 }
5920 
5921 /*@
5922   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
5923 
5924   Not collective
5925 
5926    Input Parameters:
5927 +  dm - the DM
5928 -  c - coordinate vector
5929 
5930   Notes:
5931   The coordinates of ghost points can be set using DMSetCoordinates()
5932   followed by DMGetCoordinatesLocal(). This is intended to enable the
5933   setting of ghost coordinates outside of the domain.
5934 
5935   The vector c should be destroyed by the caller.
5936 
5937   Level: intermediate
5938 
5939 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
5940 @*/
5941 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
5942 {
5943   PetscErrorCode ierr;
5944 
5945   PetscFunctionBegin;
5946   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5947   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
5948   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
5949   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
5950 
5951   dm->coordinatesLocal = c;
5952 
5953   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
5954   PetscFunctionReturn(0);
5955 }
5956 
5957 /*@
5958   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
5959 
5960   Collective on dm
5961 
5962   Input Parameter:
5963 . dm - the DM
5964 
5965   Output Parameter:
5966 . c - global coordinate vector
5967 
5968   Note:
5969   This is a borrowed reference, so the user should NOT destroy this vector
5970 
5971   Each process has only the local coordinates (does NOT have the ghost coordinates).
5972 
5973   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
5974   and (x_0,y_0,z_0,x_1,y_1,z_1...)
5975 
5976   Level: intermediate
5977 
5978 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
5979 @*/
5980 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
5981 {
5982   PetscErrorCode ierr;
5983 
5984   PetscFunctionBegin;
5985   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5986   PetscValidPointer(c,2);
5987   if (!dm->coordinates && dm->coordinatesLocal) {
5988     DM        cdm = NULL;
5989     PetscBool localized;
5990 
5991     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
5992     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
5993     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
5994     /* Block size is not correctly set by CreateGlobalVector() if coordinates are localized */
5995     if (localized) {
5996       PetscInt cdim;
5997 
5998       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
5999       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
6000     }
6001     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
6002     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
6003     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
6004   }
6005   *c = dm->coordinates;
6006   PetscFunctionReturn(0);
6007 }
6008 
6009 /*@
6010   DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that DMGetCoordinatesLocalNoncollective() can be used as non-collective afterwards.
6011 
6012   Collective on dm
6013 
6014   Input Parameter:
6015 . dm - the DM
6016 
6017   Level: advanced
6018 
6019 .seealso: DMGetCoordinatesLocalNoncollective()
6020 @*/
6021 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm)
6022 {
6023   PetscErrorCode ierr;
6024 
6025   PetscFunctionBegin;
6026   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6027   if (!dm->coordinatesLocal && dm->coordinates) {
6028     DM        cdm = NULL;
6029     PetscBool localized;
6030 
6031     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6032     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
6033     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
6034     /* Block size is not correctly set by CreateLocalVector() if coordinates are localized */
6035     if (localized) {
6036       PetscInt cdim;
6037 
6038       ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr);
6039       ierr = VecSetBlockSize(dm->coordinates, cdim);CHKERRQ(ierr);
6040     }
6041     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
6042     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
6043     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
6044   }
6045   PetscFunctionReturn(0);
6046 }
6047 
6048 /*@
6049   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
6050 
6051   Collective on dm
6052 
6053   Input Parameter:
6054 . dm - the DM
6055 
6056   Output Parameter:
6057 . c - coordinate vector
6058 
6059   Note:
6060   This is a borrowed reference, so the user should NOT destroy this vector
6061 
6062   Each process has the local and ghost coordinates
6063 
6064   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6065   and (x_0,y_0,z_0,x_1,y_1,z_1...)
6066 
6067   Level: intermediate
6068 
6069 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM(), DMGetCoordinatesLocalNoncollective()
6070 @*/
6071 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
6072 {
6073   PetscErrorCode ierr;
6074 
6075   PetscFunctionBegin;
6076   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6077   PetscValidPointer(c,2);
6078   ierr = DMGetCoordinatesLocalSetUp(dm);CHKERRQ(ierr);
6079   *c = dm->coordinatesLocal;
6080   PetscFunctionReturn(0);
6081 }
6082 
6083 /*@
6084   DMGetCoordinatesLocalNoncollective - Non-collective version of DMGetCoordinatesLocal(). Fails if global coordinates have been set and DMGetCoordinatesLocalSetUp() not called.
6085 
6086   Not collective
6087 
6088   Input Parameter:
6089 . dm - the DM
6090 
6091   Output Parameter:
6092 . c - coordinate vector
6093 
6094   Level: advanced
6095 
6096 .seealso: DMGetCoordinatesLocalSetUp(), DMGetCoordinatesLocal(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6097 @*/
6098 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c)
6099 {
6100   PetscFunctionBegin;
6101   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6102   PetscValidPointer(c,2);
6103   if (!dm->coordinatesLocal && dm->coordinates) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called");
6104   *c = dm->coordinatesLocal;
6105   PetscFunctionReturn(0);
6106 }
6107 
6108 /*@
6109   DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and section describing its layout.
6110 
6111   Not collective
6112 
6113   Input Parameter:
6114 + dm - the DM
6115 - p - the IS of points whose coordinates will be returned
6116 
6117   Output Parameter:
6118 + pCoordSection - the PetscSection describing the layout of pCoord, i.e. each point corresponds to one point in p, and DOFs correspond to coordinates
6119 - pCoord - the Vec with coordinates of points in p
6120 
6121   Note:
6122   DMGetCoordinatesLocalSetUp() must be called first. This function employs DMGetCoordinatesLocalNoncollective() so it is not collective.
6123 
6124   This creates a new vector, so the user SHOULD destroy this vector
6125 
6126   Each process has the local and ghost coordinates
6127 
6128   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
6129   and (x_0,y_0,z_0,x_1,y_1,z_1...)
6130 
6131   Level: advanced
6132 
6133 .seealso: DMSetCoordinatesLocal(), DMGetCoordinatesLocal(), DMGetCoordinatesLocalNoncollective(), DMGetCoordinatesLocalSetUp(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
6134 @*/
6135 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord)
6136 {
6137   PetscSection        cs, newcs;
6138   Vec                 coords;
6139   const PetscScalar   *arr;
6140   PetscScalar         *newarr=NULL;
6141   PetscInt            n;
6142   PetscErrorCode      ierr;
6143 
6144   PetscFunctionBegin;
6145   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6146   PetscValidHeaderSpecific(p, IS_CLASSID, 2);
6147   if (pCoordSection) PetscValidPointer(pCoordSection, 3);
6148   if (pCoord) PetscValidPointer(pCoord, 4);
6149   if (!dm->coordinatesLocal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set");
6150   if (!dm->coordinateDM || !dm->coordinateDM->localSection) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported");
6151   cs = dm->coordinateDM->localSection;
6152   coords = dm->coordinatesLocal;
6153   ierr = VecGetArrayRead(coords, &arr);CHKERRQ(ierr);
6154   ierr = PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void**)&newarr) : NULL);CHKERRQ(ierr);
6155   ierr = VecRestoreArrayRead(coords, &arr);CHKERRQ(ierr);
6156   if (pCoord) {
6157     ierr = PetscSectionGetStorageSize(newcs, &n);CHKERRQ(ierr);
6158     /* set array in two steps to mimic PETSC_OWN_POINTER */
6159     ierr = VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord);CHKERRQ(ierr);
6160     ierr = VecReplaceArray(*pCoord, newarr);CHKERRQ(ierr);
6161   } else {
6162     ierr = PetscFree(newarr);CHKERRQ(ierr);
6163   }
6164   if (pCoordSection) {*pCoordSection = newcs;}
6165   else               {ierr = PetscSectionDestroy(&newcs);CHKERRQ(ierr);}
6166   PetscFunctionReturn(0);
6167 }
6168 
6169 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field)
6170 {
6171   PetscErrorCode ierr;
6172 
6173   PetscFunctionBegin;
6174   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6175   PetscValidPointer(field,2);
6176   if (!dm->coordinateField) {
6177     if (dm->ops->createcoordinatefield) {
6178       ierr = (*dm->ops->createcoordinatefield)(dm,&dm->coordinateField);CHKERRQ(ierr);
6179     }
6180   }
6181   *field = dm->coordinateField;
6182   PetscFunctionReturn(0);
6183 }
6184 
6185 PetscErrorCode DMSetCoordinateField(DM dm, DMField field)
6186 {
6187   PetscErrorCode ierr;
6188 
6189   PetscFunctionBegin;
6190   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6191   if (field) PetscValidHeaderSpecific(field,DMFIELD_CLASSID,2);
6192   ierr = PetscObjectReference((PetscObject)field);CHKERRQ(ierr);
6193   ierr = DMFieldDestroy(&dm->coordinateField);CHKERRQ(ierr);
6194   dm->coordinateField = field;
6195   PetscFunctionReturn(0);
6196 }
6197 
6198 /*@
6199   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
6200 
6201   Collective on dm
6202 
6203   Input Parameter:
6204 . dm - the DM
6205 
6206   Output Parameter:
6207 . cdm - coordinate DM
6208 
6209   Level: intermediate
6210 
6211 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6212 @*/
6213 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
6214 {
6215   PetscErrorCode ierr;
6216 
6217   PetscFunctionBegin;
6218   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6219   PetscValidPointer(cdm,2);
6220   if (!dm->coordinateDM) {
6221     DM cdm;
6222 
6223     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
6224     ierr = (*dm->ops->createcoordinatedm)(dm, &cdm);CHKERRQ(ierr);
6225     /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup
6226      * until the call to CreateCoordinateDM) */
6227     ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
6228     dm->coordinateDM = cdm;
6229   }
6230   *cdm = dm->coordinateDM;
6231   PetscFunctionReturn(0);
6232 }
6233 
6234 /*@
6235   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
6236 
6237   Logically Collective on dm
6238 
6239   Input Parameters:
6240 + dm - the DM
6241 - cdm - coordinate DM
6242 
6243   Level: intermediate
6244 
6245 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
6246 @*/
6247 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
6248 {
6249   PetscErrorCode ierr;
6250 
6251   PetscFunctionBegin;
6252   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6253   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
6254   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
6255   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
6256   dm->coordinateDM = cdm;
6257   PetscFunctionReturn(0);
6258 }
6259 
6260 /*@
6261   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
6262 
6263   Not Collective
6264 
6265   Input Parameter:
6266 . dm - The DM object
6267 
6268   Output Parameter:
6269 . dim - The embedding dimension
6270 
6271   Level: intermediate
6272 
6273 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6274 @*/
6275 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
6276 {
6277   PetscFunctionBegin;
6278   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6279   PetscValidIntPointer(dim, 2);
6280   if (dm->dimEmbed == PETSC_DEFAULT) {
6281     dm->dimEmbed = dm->dim;
6282   }
6283   *dim = dm->dimEmbed;
6284   PetscFunctionReturn(0);
6285 }
6286 
6287 /*@
6288   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
6289 
6290   Not Collective
6291 
6292   Input Parameters:
6293 + dm  - The DM object
6294 - dim - The embedding dimension
6295 
6296   Level: intermediate
6297 
6298 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6299 @*/
6300 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
6301 {
6302   PetscDS        ds;
6303   PetscErrorCode ierr;
6304 
6305   PetscFunctionBegin;
6306   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6307   dm->dimEmbed = dim;
6308   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
6309   ierr = PetscDSSetCoordinateDimension(ds, dim);CHKERRQ(ierr);
6310   PetscFunctionReturn(0);
6311 }
6312 
6313 /*@
6314   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6315 
6316   Collective on dm
6317 
6318   Input Parameter:
6319 . dm - The DM object
6320 
6321   Output Parameter:
6322 . section - The PetscSection object
6323 
6324   Level: intermediate
6325 
6326 .seealso: DMGetCoordinateDM(), DMGetLocalSection(), DMSetLocalSection()
6327 @*/
6328 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
6329 {
6330   DM             cdm;
6331   PetscErrorCode ierr;
6332 
6333   PetscFunctionBegin;
6334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6335   PetscValidPointer(section, 2);
6336   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6337   ierr = DMGetLocalSection(cdm, section);CHKERRQ(ierr);
6338   PetscFunctionReturn(0);
6339 }
6340 
6341 /*@
6342   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
6343 
6344   Not Collective
6345 
6346   Input Parameters:
6347 + dm      - The DM object
6348 . dim     - The embedding dimension, or PETSC_DETERMINE
6349 - section - The PetscSection object
6350 
6351   Level: intermediate
6352 
6353 .seealso: DMGetCoordinateSection(), DMGetLocalSection(), DMSetLocalSection()
6354 @*/
6355 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
6356 {
6357   DM             cdm;
6358   PetscErrorCode ierr;
6359 
6360   PetscFunctionBegin;
6361   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6362   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
6363   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6364   ierr = DMSetLocalSection(cdm, section);CHKERRQ(ierr);
6365   if (dim == PETSC_DETERMINE) {
6366     PetscInt d = PETSC_DEFAULT;
6367     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
6368 
6369     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6370     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6371     pStart = PetscMax(vStart, pStart);
6372     pEnd   = PetscMin(vEnd, pEnd);
6373     for (v = pStart; v < pEnd; ++v) {
6374       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
6375       if (dd) {d = dd; break;}
6376     }
6377     if (d >= 0) {ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);}
6378   }
6379   PetscFunctionReturn(0);
6380 }
6381 
6382 /*@
6383   DMProjectCoordinates - Project coordinates to a different space
6384 
6385   Input Parameters:
6386 + dm      - The DM object
6387 - disc    - The new coordinate discretization
6388 
6389   Level: intermediate
6390 
6391 .seealso: DMGetCoordinateField()
6392 @*/
6393 PetscErrorCode DMProjectCoordinates(DM dm, PetscFE disc)
6394 {
6395   PetscObject    discOld;
6396   PetscClassId   classid;
6397   DM             cdmOld,cdmNew;
6398   Vec            coordsOld,coordsNew;
6399   Mat            matInterp;
6400   PetscErrorCode ierr;
6401 
6402   PetscFunctionBegin;
6403   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6404   PetscValidHeaderSpecific(disc,PETSCFE_CLASSID,2);
6405 
6406   ierr = DMGetCoordinateDM(dm, &cdmOld);CHKERRQ(ierr);
6407   /* Check current discretization is compatible */
6408   ierr = DMGetField(cdmOld, 0, NULL, &discOld);CHKERRQ(ierr);
6409   ierr = PetscObjectGetClassId(discOld, &classid);CHKERRQ(ierr);
6410   if (classid != PETSCFE_CLASSID) {
6411     if (classid == PETSC_CONTAINER_CLASSID) {
6412       PetscFE        feLinear;
6413       DMPolytopeType ct;
6414       PetscInt       dim, dE, cStart;
6415       PetscBool      simplex;
6416 
6417       /* Assume linear vertex coordinates */
6418       ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6419       ierr = DMGetCoordinateDim(dm, &dE);CHKERRQ(ierr);
6420       ierr = DMPlexGetHeightStratum(cdmOld, 0, &cStart, NULL);CHKERRQ(ierr);
6421       ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr);
6422       switch (ct) {
6423         case DM_POLYTOPE_TRI_PRISM:
6424         case DM_POLYTOPE_TRI_PRISM_TENSOR:
6425           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot autoamtically create coordinate space for prisms");
6426         default: break;
6427       }
6428       simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE;
6429       ierr = PetscFECreateLagrange(PETSC_COMM_SELF, dim, dE, simplex, 1, -1, &feLinear);CHKERRQ(ierr);
6430       ierr = DMSetField(cdmOld, 0, NULL, (PetscObject) feLinear);CHKERRQ(ierr);
6431       ierr = PetscFEDestroy(&feLinear);CHKERRQ(ierr);
6432       ierr = DMCreateDS(cdmOld);CHKERRQ(ierr);
6433     } else {
6434       const char *discname;
6435 
6436       ierr = PetscObjectGetType(discOld, &discname);CHKERRQ(ierr);
6437       SETERRQ1(PetscObjectComm(discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname);
6438     }
6439   }
6440   /* Make a fresh clone of the coordinate DM */
6441   ierr = DMClone(cdmOld, &cdmNew);CHKERRQ(ierr);
6442   ierr = DMSetField(cdmNew, 0, NULL, (PetscObject) disc);CHKERRQ(ierr);
6443   ierr = DMCreateDS(cdmNew);CHKERRQ(ierr);
6444   /* Project the coordinate vector from old to new space  */
6445   ierr = DMGetCoordinates(dm, &coordsOld);CHKERRQ(ierr);
6446   ierr = DMCreateGlobalVector(cdmNew, &coordsNew);CHKERRQ(ierr);
6447   ierr = DMCreateInterpolation(cdmOld, cdmNew, &matInterp, NULL);CHKERRQ(ierr);
6448   ierr = MatInterpolate(matInterp, coordsOld, coordsNew);CHKERRQ(ierr);
6449   ierr = MatDestroy(&matInterp);CHKERRQ(ierr);
6450   /* Set new coordinate structures */
6451   ierr = DMSetCoordinateField(dm, NULL);CHKERRQ(ierr);
6452   ierr = DMSetCoordinateDM(dm, cdmNew);CHKERRQ(ierr);
6453   ierr = DMSetCoordinates(dm, coordsNew);CHKERRQ(ierr);
6454   ierr = VecDestroy(&coordsNew);CHKERRQ(ierr);
6455   ierr = DMDestroy(&cdmNew);CHKERRQ(ierr);
6456   PetscFunctionReturn(0);
6457 }
6458 
6459 /*@C
6460   DMGetPeriodicity - Get the description of mesh periodicity
6461 
6462   Input Parameters:
6463 . dm      - The DM object
6464 
6465   Output Parameters:
6466 + per     - Whether the DM is periodic or not
6467 . maxCell - Over distances greater than this, we can assume a point has crossed over to another sheet, when trying to localize cell coordinates
6468 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6469 - bd      - This describes the type of periodicity in each topological dimension
6470 
6471   Level: developer
6472 
6473 .seealso: DMGetPeriodicity()
6474 @*/
6475 PetscErrorCode DMGetPeriodicity(DM dm, PetscBool *per, const PetscReal **maxCell, const PetscReal **L, const DMBoundaryType **bd)
6476 {
6477   PetscFunctionBegin;
6478   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6479   if (per)     *per     = dm->periodic;
6480   if (L)       *L       = dm->L;
6481   if (maxCell) *maxCell = dm->maxCell;
6482   if (bd)      *bd      = dm->bdtype;
6483   PetscFunctionReturn(0);
6484 }
6485 
6486 /*@C
6487   DMSetPeriodicity - Set the description of mesh periodicity
6488 
6489   Input Parameters:
6490 + dm      - The DM object
6491 . per     - Whether the DM is periodic or not.
6492 . 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.
6493 . L       - If we assume the mesh is a torus, this is the length of each coordinate
6494 - bd      - This describes the type of periodicity in each topological dimension
6495 
6496   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.
6497 
6498   Level: developer
6499 
6500 .seealso: DMGetPeriodicity()
6501 @*/
6502 PetscErrorCode DMSetPeriodicity(DM dm, PetscBool per, const PetscReal maxCell[], const PetscReal L[], const DMBoundaryType bd[])
6503 {
6504   PetscInt       dim, d;
6505   PetscErrorCode ierr;
6506 
6507   PetscFunctionBegin;
6508   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6509   PetscValidLogicalCollectiveBool(dm,per,2);
6510   if (maxCell) {PetscValidRealPointer(maxCell,3);}
6511   if (L)       {PetscValidRealPointer(L,4);}
6512   if (bd)      {PetscValidPointer(bd,5);}
6513   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6514   if (maxCell) {
6515     if (!dm->maxCell) {ierr = PetscMalloc1(dim, &dm->maxCell);CHKERRQ(ierr);}
6516     for (d = 0; d < dim; ++d) dm->maxCell[d] = maxCell[d];
6517   } else { /* remove maxCell information to disable automatic computation of localized vertices */
6518     ierr = PetscFree(dm->maxCell);CHKERRQ(ierr);
6519   }
6520 
6521   if (L) {
6522     if (!dm->L) {ierr = PetscMalloc1(dim, &dm->L);CHKERRQ(ierr);}
6523     for (d = 0; d < dim; ++d) dm->L[d] = L[d];
6524   }
6525   if (bd) {
6526     if (!dm->bdtype) {ierr = PetscMalloc1(dim, &dm->bdtype);CHKERRQ(ierr);}
6527     for (d = 0; d < dim; ++d) dm->bdtype[d] = bd[d];
6528   }
6529   dm->periodic = per;
6530   PetscFunctionReturn(0);
6531 }
6532 
6533 /*@
6534   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.
6535 
6536   Input Parameters:
6537 + dm     - The DM
6538 . in     - The input coordinate point (dim numbers)
6539 - endpoint - Include the endpoint L_i
6540 
6541   Output Parameter:
6542 . out - The localized coordinate point
6543 
6544   Level: developer
6545 
6546 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6547 @*/
6548 PetscErrorCode DMLocalizeCoordinate(DM dm, const PetscScalar in[], PetscBool endpoint, PetscScalar out[])
6549 {
6550   PetscInt       dim, d;
6551   PetscErrorCode ierr;
6552 
6553   PetscFunctionBegin;
6554   ierr = DMGetCoordinateDim(dm, &dim);CHKERRQ(ierr);
6555   if (!dm->maxCell) {
6556     for (d = 0; d < dim; ++d) out[d] = in[d];
6557   } else {
6558     if (endpoint) {
6559       for (d = 0; d < dim; ++d) {
6560         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)) {
6561           out[d] = in[d] - dm->L[d]*(PetscFloorReal(PetscRealPart(in[d])/dm->L[d]) - 1);
6562         } else {
6563           out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6564         }
6565       }
6566     } else {
6567       for (d = 0; d < dim; ++d) {
6568         out[d] = in[d] - dm->L[d]*PetscFloorReal(PetscRealPart(in[d])/dm->L[d]);
6569       }
6570     }
6571   }
6572   PetscFunctionReturn(0);
6573 }
6574 
6575 /*
6576   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.
6577 
6578   Input Parameters:
6579 + dm     - The DM
6580 . dim    - The spatial dimension
6581 . anchor - The anchor point, the input point can be no more than maxCell away from it
6582 - in     - The input coordinate point (dim numbers)
6583 
6584   Output Parameter:
6585 . out - The localized coordinate point
6586 
6587   Level: developer
6588 
6589   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
6590 
6591 .seealso: DMLocalizeCoordinates(), DMLocalizeAddCoordinate()
6592 */
6593 PetscErrorCode DMLocalizeCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6594 {
6595   PetscInt d;
6596 
6597   PetscFunctionBegin;
6598   if (!dm->maxCell) {
6599     for (d = 0; d < dim; ++d) out[d] = in[d];
6600   } else {
6601     for (d = 0; d < dim; ++d) {
6602       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > dm->maxCell[d])) {
6603         out[d] = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6604       } else {
6605         out[d] = in[d];
6606       }
6607     }
6608   }
6609   PetscFunctionReturn(0);
6610 }
6611 
6612 PetscErrorCode DMLocalizeCoordinateReal_Internal(DM dm, PetscInt dim, const PetscReal anchor[], const PetscReal in[], PetscReal out[])
6613 {
6614   PetscInt d;
6615 
6616   PetscFunctionBegin;
6617   if (!dm->maxCell) {
6618     for (d = 0; d < dim; ++d) out[d] = in[d];
6619   } else {
6620     for (d = 0; d < dim; ++d) {
6621       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsReal(anchor[d] - in[d]) > dm->maxCell[d])) {
6622         out[d] = anchor[d] > in[d] ? dm->L[d] + in[d] : in[d] - dm->L[d];
6623       } else {
6624         out[d] = in[d];
6625       }
6626     }
6627   }
6628   PetscFunctionReturn(0);
6629 }
6630 
6631 /*
6632   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.
6633 
6634   Input Parameters:
6635 + dm     - The DM
6636 . dim    - The spatial dimension
6637 . anchor - The anchor point, the input point can be no more than maxCell away from it
6638 . in     - The input coordinate delta (dim numbers)
6639 - out    - The input coordinate point (dim numbers)
6640 
6641   Output Parameter:
6642 . out    - The localized coordinate in + out
6643 
6644   Level: developer
6645 
6646   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
6647 
6648 .seealso: DMLocalizeCoordinates(), DMLocalizeCoordinate()
6649 */
6650 PetscErrorCode DMLocalizeAddCoordinate_Internal(DM dm, PetscInt dim, const PetscScalar anchor[], const PetscScalar in[], PetscScalar out[])
6651 {
6652   PetscInt d;
6653 
6654   PetscFunctionBegin;
6655   if (!dm->maxCell) {
6656     for (d = 0; d < dim; ++d) out[d] += in[d];
6657   } else {
6658     for (d = 0; d < dim; ++d) {
6659       const PetscReal maxC = dm->maxCell[d];
6660 
6661       if ((dm->bdtype[d] != DM_BOUNDARY_NONE) && (PetscAbsScalar(anchor[d] - in[d]) > maxC)) {
6662         const PetscScalar newCoord = PetscRealPart(anchor[d]) > PetscRealPart(in[d]) ? dm->L[d] + in[d] : in[d] - dm->L[d];
6663 
6664         if (PetscAbsScalar(newCoord - anchor[d]) > maxC)
6665           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]));
6666         out[d] += newCoord;
6667       } else {
6668         out[d] += in[d];
6669       }
6670     }
6671   }
6672   PetscFunctionReturn(0);
6673 }
6674 
6675 /*@
6676   DMGetCoordinatesLocalizedLocal - Check if the DM coordinates have been localized for cells on this process
6677 
6678   Not collective
6679 
6680   Input Parameter:
6681 . dm - The DM
6682 
6683   Output Parameter:
6684   areLocalized - True if localized
6685 
6686   Level: developer
6687 
6688 .seealso: DMLocalizeCoordinates(), DMGetCoordinatesLocalized(), DMSetPeriodicity()
6689 @*/
6690 PetscErrorCode DMGetCoordinatesLocalizedLocal(DM dm,PetscBool *areLocalized)
6691 {
6692   DM             cdm;
6693   PetscSection   coordSection;
6694   PetscInt       cStart, cEnd, sStart, sEnd, c, dof;
6695   PetscBool      isPlex, alreadyLocalized;
6696   PetscErrorCode ierr;
6697 
6698   PetscFunctionBegin;
6699   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6700   PetscValidBoolPointer(areLocalized, 2);
6701   *areLocalized = PETSC_FALSE;
6702 
6703   /* We need some generic way of refering to cells/vertices */
6704   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6705   ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isPlex);CHKERRQ(ierr);
6706   if (!isPlex) PetscFunctionReturn(0);
6707 
6708   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6709   ierr = DMPlexGetHeightStratum(cdm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6710   ierr = PetscSectionGetChart(coordSection, &sStart, &sEnd);CHKERRQ(ierr);
6711   alreadyLocalized = PETSC_FALSE;
6712   for (c = cStart; c < cEnd; ++c) {
6713     if (c < sStart || c >= sEnd) continue;
6714     ierr = PetscSectionGetDof(coordSection, c, &dof);CHKERRQ(ierr);
6715     if (dof) { alreadyLocalized = PETSC_TRUE; break; }
6716   }
6717   *areLocalized = alreadyLocalized;
6718   PetscFunctionReturn(0);
6719 }
6720 
6721 /*@
6722   DMGetCoordinatesLocalized - Check if the DM coordinates have been localized for cells
6723 
6724   Collective on dm
6725 
6726   Input Parameter:
6727 . dm - The DM
6728 
6729   Output Parameter:
6730   areLocalized - True if localized
6731 
6732   Level: developer
6733 
6734 .seealso: DMLocalizeCoordinates(), DMSetPeriodicity(), DMGetCoordinatesLocalizedLocal()
6735 @*/
6736 PetscErrorCode DMGetCoordinatesLocalized(DM dm,PetscBool *areLocalized)
6737 {
6738   PetscBool      localized;
6739   PetscErrorCode ierr;
6740 
6741   PetscFunctionBegin;
6742   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6743   PetscValidBoolPointer(areLocalized, 2);
6744   ierr = DMGetCoordinatesLocalizedLocal(dm,&localized);CHKERRQ(ierr);
6745   ierr = MPIU_Allreduce(&localized,areLocalized,1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6746   PetscFunctionReturn(0);
6747 }
6748 
6749 /*@
6750   DMLocalizeCoordinates - If a mesh is periodic, create local coordinates for cells having periodic faces
6751 
6752   Collective on dm
6753 
6754   Input Parameter:
6755 . dm - The DM
6756 
6757   Level: developer
6758 
6759 .seealso: DMSetPeriodicity(), DMLocalizeCoordinate(), DMLocalizeAddCoordinate()
6760 @*/
6761 PetscErrorCode DMLocalizeCoordinates(DM dm)
6762 {
6763   DM             cdm;
6764   PetscSection   coordSection, cSection;
6765   Vec            coordinates,  cVec;
6766   PetscScalar   *coords, *coords2, *anchor, *localized;
6767   PetscInt       Nc, vStart, vEnd, v, sStart, sEnd, newStart = PETSC_MAX_INT, newEnd = PETSC_MIN_INT, dof, d, off, off2, bs, coordSize;
6768   PetscBool      alreadyLocalized, alreadyLocalizedGlobal;
6769   PetscInt       maxHeight = 0, h;
6770   PetscInt       *pStart = NULL, *pEnd = NULL;
6771   PetscErrorCode ierr;
6772 
6773   PetscFunctionBegin;
6774   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6775   if (!dm->periodic) PetscFunctionReturn(0);
6776   ierr = DMGetCoordinatesLocalized(dm, &alreadyLocalized);CHKERRQ(ierr);
6777   if (alreadyLocalized) PetscFunctionReturn(0);
6778 
6779   /* We need some generic way of refering to cells/vertices */
6780   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6781   {
6782     PetscBool isplex;
6783 
6784     ierr = PetscObjectTypeCompare((PetscObject) cdm, DMPLEX, &isplex);CHKERRQ(ierr);
6785     if (isplex) {
6786       ierr = DMPlexGetDepthStratum(cdm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6787       ierr = DMPlexGetMaxProjectionHeight(cdm,&maxHeight);CHKERRQ(ierr);
6788       ierr = DMGetWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6789       pEnd = &pStart[maxHeight + 1];
6790       newStart = vStart;
6791       newEnd   = vEnd;
6792       for (h = 0; h <= maxHeight; h++) {
6793         ierr = DMPlexGetHeightStratum(cdm, h, &pStart[h], &pEnd[h]);CHKERRQ(ierr);
6794         newStart = PetscMin(newStart,pStart[h]);
6795         newEnd   = PetscMax(newEnd,pEnd[h]);
6796       }
6797     } else SETERRQ(PetscObjectComm((PetscObject) cdm), PETSC_ERR_ARG_WRONG, "Coordinate localization requires a DMPLEX coordinate DM");
6798   }
6799   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6800   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing local coordinates vector");
6801   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6802   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6803   ierr = PetscSectionGetChart(coordSection,&sStart,&sEnd);CHKERRQ(ierr);
6804 
6805   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &cSection);CHKERRQ(ierr);
6806   ierr = PetscSectionSetNumFields(cSection, 1);CHKERRQ(ierr);
6807   ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
6808   ierr = PetscSectionSetFieldComponents(cSection, 0, Nc);CHKERRQ(ierr);
6809   ierr = PetscSectionSetChart(cSection, newStart, newEnd);CHKERRQ(ierr);
6810 
6811   ierr = DMGetWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6812   localized = &anchor[bs];
6813   alreadyLocalized = alreadyLocalizedGlobal = PETSC_TRUE;
6814   for (h = 0; h <= maxHeight; h++) {
6815     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6816 
6817     for (c = cStart; c < cEnd; ++c) {
6818       PetscScalar *cellCoords = NULL;
6819       PetscInt     b;
6820 
6821       if (c < sStart || c >= sEnd) alreadyLocalized = PETSC_FALSE;
6822       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6823       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6824       for (d = 0; d < dof/bs; ++d) {
6825         ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], localized);CHKERRQ(ierr);
6826         for (b = 0; b < bs; b++) {
6827           if (cellCoords[d*bs + b] != localized[b]) break;
6828         }
6829         if (b < bs) break;
6830       }
6831       if (d < dof/bs) {
6832         if (c >= sStart && c < sEnd) {
6833           PetscInt cdof;
6834 
6835           ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6836           if (cdof != dof) alreadyLocalized = PETSC_FALSE;
6837         }
6838         ierr = PetscSectionSetDof(cSection, c, dof);CHKERRQ(ierr);
6839         ierr = PetscSectionSetFieldDof(cSection, c, 0, dof);CHKERRQ(ierr);
6840       }
6841       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6842     }
6843   }
6844   ierr = MPI_Allreduce(&alreadyLocalized,&alreadyLocalizedGlobal,1,MPIU_BOOL,MPI_LAND,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
6845   if (alreadyLocalizedGlobal) {
6846     ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6847     ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6848     ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6849     PetscFunctionReturn(0);
6850   }
6851   for (v = vStart; v < vEnd; ++v) {
6852     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6853     ierr = PetscSectionSetDof(cSection, v, dof);CHKERRQ(ierr);
6854     ierr = PetscSectionSetFieldDof(cSection, v, 0, dof);CHKERRQ(ierr);
6855   }
6856   ierr = PetscSectionSetUp(cSection);CHKERRQ(ierr);
6857   ierr = PetscSectionGetStorageSize(cSection, &coordSize);CHKERRQ(ierr);
6858   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
6859   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
6860   ierr = VecSetBlockSize(cVec, bs);CHKERRQ(ierr);
6861   ierr = VecSetSizes(cVec, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
6862   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
6863   ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6864   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
6865   for (v = vStart; v < vEnd; ++v) {
6866     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
6867     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6868     ierr = PetscSectionGetOffset(cSection,     v, &off2);CHKERRQ(ierr);
6869     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
6870   }
6871   for (h = 0; h <= maxHeight; h++) {
6872     PetscInt cStart = pStart[h], cEnd = pEnd[h], c;
6873 
6874     for (c = cStart; c < cEnd; ++c) {
6875       PetscScalar *cellCoords = NULL;
6876       PetscInt     b, cdof;
6877 
6878       ierr = PetscSectionGetDof(cSection,c,&cdof);CHKERRQ(ierr);
6879       if (!cdof) continue;
6880       ierr = DMPlexVecGetClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6881       ierr = PetscSectionGetOffset(cSection, c, &off2);CHKERRQ(ierr);
6882       for (b = 0; b < bs; ++b) anchor[b] = cellCoords[b];
6883       for (d = 0; d < dof/bs; ++d) {ierr = DMLocalizeCoordinate_Internal(dm, bs, anchor, &cellCoords[d*bs], &coords2[off2+d*bs]);CHKERRQ(ierr);}
6884       ierr = DMPlexVecRestoreClosure(cdm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
6885     }
6886   }
6887   ierr = DMRestoreWorkArray(dm, 2 * bs, MPIU_SCALAR, &anchor);CHKERRQ(ierr);
6888   ierr = DMRestoreWorkArray(dm,2*(maxHeight + 1),MPIU_INT,&pStart);CHKERRQ(ierr);
6889   ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
6890   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
6891   ierr = DMSetCoordinateSection(dm, PETSC_DETERMINE, cSection);CHKERRQ(ierr);
6892   ierr = DMSetCoordinatesLocal(dm, cVec);CHKERRQ(ierr);
6893   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
6894   ierr = PetscSectionDestroy(&cSection);CHKERRQ(ierr);
6895   PetscFunctionReturn(0);
6896 }
6897 
6898 /*@
6899   DMLocatePoints - Locate the points in v in the mesh and return a PetscSF of the containing cells
6900 
6901   Collective on v (see explanation below)
6902 
6903   Input Parameters:
6904 + dm - The DM
6905 . v - The Vec of points
6906 . ltype - The type of point location, e.g. DM_POINTLOCATION_NONE or DM_POINTLOCATION_NEAREST
6907 - cells - Points to either NULL, or a PetscSF with guesses for which cells contain each point.
6908 
6909   Output Parameter:
6910 + v - The Vec of points, which now contains the nearest mesh points to the given points if DM_POINTLOCATION_NEAREST is used
6911 - cells - The PetscSF containing the ranks and local indices of the containing points.
6912 
6913 
6914   Level: developer
6915 
6916   Notes:
6917   To do a search of the local cells of the mesh, v should have PETSC_COMM_SELF as its communicator.
6918   To do a search of all the cells in the distributed mesh, v should have the same communicator as dm.
6919 
6920   If *cellSF is NULL on input, a PetscSF will be created.
6921   If *cellSF is not NULL on input, it should point to an existing PetscSF, whose graph will be used as initial guesses.
6922 
6923   An array that maps each point to its containing cell can be obtained with
6924 
6925 $    const PetscSFNode *cells;
6926 $    PetscInt           nFound;
6927 $    const PetscInt    *found;
6928 $
6929 $    PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells);
6930 
6931   Where cells[i].rank is the rank of the cell containing point found[i] (or i if found == NULL), and cells[i].index is
6932   the index of the cell in its rank's local numbering.
6933 
6934 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal(), DMPointLocationType
6935 @*/
6936 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF)
6937 {
6938   PetscErrorCode ierr;
6939 
6940   PetscFunctionBegin;
6941   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6942   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
6943   PetscValidPointer(cellSF,4);
6944   if (*cellSF) {
6945     PetscMPIInt result;
6946 
6947     PetscValidHeaderSpecific(*cellSF,PETSCSF_CLASSID,4);
6948     ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)v),PetscObjectComm((PetscObject)*cellSF),&result);CHKERRQ(ierr);
6949     if (result != MPI_IDENT && result != MPI_CONGRUENT) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"cellSF must have a communicator congruent to v's");
6950   } else {
6951     ierr = PetscSFCreate(PetscObjectComm((PetscObject)v),cellSF);CHKERRQ(ierr);
6952   }
6953   if (!dm->ops->locatepoints) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
6954   ierr = PetscLogEventBegin(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6955   ierr = (*dm->ops->locatepoints)(dm,v,ltype,*cellSF);CHKERRQ(ierr);
6956   ierr = PetscLogEventEnd(DM_LocatePoints,dm,0,0,0);CHKERRQ(ierr);
6957   PetscFunctionReturn(0);
6958 }
6959 
6960 /*@
6961   DMGetOutputDM - Retrieve the DM associated with the layout for output
6962 
6963   Collective on dm
6964 
6965   Input Parameter:
6966 . dm - The original DM
6967 
6968   Output Parameter:
6969 . odm - The DM which provides the layout for output
6970 
6971   Level: intermediate
6972 
6973 .seealso: VecView(), DMGetGlobalSection()
6974 @*/
6975 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
6976 {
6977   PetscSection   section;
6978   PetscBool      hasConstraints, ghasConstraints;
6979   PetscErrorCode ierr;
6980 
6981   PetscFunctionBegin;
6982   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6983   PetscValidPointer(odm,2);
6984   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
6985   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
6986   ierr = MPI_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6987   if (!ghasConstraints) {
6988     *odm = dm;
6989     PetscFunctionReturn(0);
6990   }
6991   if (!dm->dmBC) {
6992     PetscSection newSection, gsection;
6993     PetscSF      sf;
6994 
6995     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
6996     ierr = DMCopyDisc(dm, dm->dmBC);CHKERRQ(ierr);
6997     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
6998     ierr = DMSetLocalSection(dm->dmBC, newSection);CHKERRQ(ierr);
6999     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
7000     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
7001     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection);CHKERRQ(ierr);
7002     ierr = DMSetGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
7003     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
7004   }
7005   *odm = dm->dmBC;
7006   PetscFunctionReturn(0);
7007 }
7008 
7009 /*@
7010   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
7011 
7012   Input Parameter:
7013 . dm - The original DM
7014 
7015   Output Parameters:
7016 + num - The output sequence number
7017 - val - The output sequence value
7018 
7019   Level: intermediate
7020 
7021   Note: This is intended for output that should appear in sequence, for instance
7022   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7023 
7024 .seealso: VecView()
7025 @*/
7026 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
7027 {
7028   PetscFunctionBegin;
7029   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7030   if (num) {PetscValidIntPointer(num,2); *num = dm->outputSequenceNum;}
7031   if (val) {PetscValidRealPointer(val,3);*val = dm->outputSequenceVal;}
7032   PetscFunctionReturn(0);
7033 }
7034 
7035 /*@
7036   DMSetOutputSequenceNumber - Set the sequence number/value for output
7037 
7038   Input Parameters:
7039 + dm - The original DM
7040 . num - The output sequence number
7041 - val - The output sequence value
7042 
7043   Level: intermediate
7044 
7045   Note: This is intended for output that should appear in sequence, for instance
7046   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7047 
7048 .seealso: VecView()
7049 @*/
7050 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
7051 {
7052   PetscFunctionBegin;
7053   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7054   dm->outputSequenceNum = num;
7055   dm->outputSequenceVal = val;
7056   PetscFunctionReturn(0);
7057 }
7058 
7059 /*@C
7060   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
7061 
7062   Input Parameters:
7063 + dm   - The original DM
7064 . name - The sequence name
7065 - num  - The output sequence number
7066 
7067   Output Parameter:
7068 . val  - The output sequence value
7069 
7070   Level: intermediate
7071 
7072   Note: This is intended for output that should appear in sequence, for instance
7073   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
7074 
7075 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
7076 @*/
7077 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
7078 {
7079   PetscBool      ishdf5;
7080   PetscErrorCode ierr;
7081 
7082   PetscFunctionBegin;
7083   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
7084   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
7085   PetscValidRealPointer(val,4);
7086   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
7087   if (ishdf5) {
7088 #if defined(PETSC_HAVE_HDF5)
7089     PetscScalar value;
7090 
7091     ierr = DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer);CHKERRQ(ierr);
7092     *val = PetscRealPart(value);
7093 #endif
7094   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
7095   PetscFunctionReturn(0);
7096 }
7097 
7098 /*@
7099   DMGetUseNatural - Get the flag for creating a mapping to the natural order on distribution
7100 
7101   Not collective
7102 
7103   Input Parameter:
7104 . dm - The DM
7105 
7106   Output Parameter:
7107 . useNatural - The flag to build the mapping to a natural order during distribution
7108 
7109   Level: beginner
7110 
7111 .seealso: DMSetUseNatural(), DMCreate()
7112 @*/
7113 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural)
7114 {
7115   PetscFunctionBegin;
7116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7117   PetscValidBoolPointer(useNatural, 2);
7118   *useNatural = dm->useNatural;
7119   PetscFunctionReturn(0);
7120 }
7121 
7122 /*@
7123   DMSetUseNatural - Set the flag for creating a mapping to the natural order after distribution
7124 
7125   Collective on dm
7126 
7127   Input Parameters:
7128 + dm - The DM
7129 - useNatural - The flag to build the mapping to a natural order during distribution
7130 
7131   Note: This also causes the map to be build after DMCreateSubDM() and DMCreateSuperDM()
7132 
7133   Level: beginner
7134 
7135 .seealso: DMGetUseNatural(), DMCreate(), DMPlexDistribute(), DMCreateSubDM(), DMCreateSuperDM()
7136 @*/
7137 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural)
7138 {
7139   PetscFunctionBegin;
7140   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7141   PetscValidLogicalCollectiveBool(dm, useNatural, 2);
7142   dm->useNatural = useNatural;
7143   PetscFunctionReturn(0);
7144 }
7145 
7146 
7147 /*@C
7148   DMCreateLabel - Create a label of the given name if it does not already exist
7149 
7150   Not Collective
7151 
7152   Input Parameters:
7153 + dm   - The DM object
7154 - name - The label name
7155 
7156   Level: intermediate
7157 
7158 .seealso: DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7159 @*/
7160 PetscErrorCode DMCreateLabel(DM dm, const char name[])
7161 {
7162   PetscBool      flg;
7163   DMLabel        label;
7164   PetscErrorCode ierr;
7165 
7166   PetscFunctionBegin;
7167   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7168   PetscValidCharPointer(name, 2);
7169   ierr = DMHasLabel(dm, name, &flg);CHKERRQ(ierr);
7170   if (!flg) {
7171     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &label);CHKERRQ(ierr);
7172     ierr = DMAddLabel(dm, label);CHKERRQ(ierr);
7173     ierr = DMLabelDestroy(&label);CHKERRQ(ierr);
7174   }
7175   PetscFunctionReturn(0);
7176 }
7177 
7178 /*@C
7179   DMCreateLabelAtIndex - Create a label of the given name at the iven index. If it already exists, move it to this index.
7180 
7181   Not Collective
7182 
7183   Input Parameters:
7184 + dm   - The DM object
7185 . l    - The index for the label
7186 - name - The label name
7187 
7188   Level: intermediate
7189 
7190 .seealso: DMCreateLabel(), DMLabelCreate(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7191 @*/
7192 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[])
7193 {
7194   DMLabelLink    orig, prev = NULL;
7195   DMLabel        label;
7196   PetscInt       Nl, m;
7197   PetscBool      flg, match;
7198   const char    *lname;
7199   PetscErrorCode ierr;
7200 
7201   PetscFunctionBegin;
7202   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7203   PetscValidCharPointer(name, 2);
7204   ierr = DMHasLabel(dm, name, &flg);CHKERRQ(ierr);
7205   if (!flg) {
7206     ierr = DMLabelCreate(PETSC_COMM_SELF, name, &label);CHKERRQ(ierr);
7207     ierr = DMAddLabel(dm, label);CHKERRQ(ierr);
7208     ierr = DMLabelDestroy(&label);CHKERRQ(ierr);
7209   }
7210   ierr = DMGetNumLabels(dm, &Nl);CHKERRQ(ierr);
7211   if (l >= Nl) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %D must be in [0, %D)", l, Nl);
7212   for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) {
7213     ierr = PetscObjectGetName((PetscObject) orig->label, &lname);CHKERRQ(ierr);
7214     ierr = PetscStrcmp(name, lname, &match);CHKERRQ(ierr);
7215     if (match) break;
7216   }
7217   if (m == l) PetscFunctionReturn(0);
7218   if (!m) dm->labels = orig->next;
7219   else    prev->next = orig->next;
7220   if (!l) {
7221     orig->next = dm->labels;
7222     dm->labels = orig;
7223   } else {
7224     for (m = 0, prev = dm->labels; m < l-1; ++m, prev = prev->next);
7225     orig->next = prev->next;
7226     prev->next = orig;
7227   }
7228   PetscFunctionReturn(0);
7229 }
7230 
7231 /*@C
7232   DMGetLabelValue - Get the value in a Sieve Label for the given point, with 0 as the default
7233 
7234   Not Collective
7235 
7236   Input Parameters:
7237 + dm   - The DM object
7238 . name - The label name
7239 - point - The mesh point
7240 
7241   Output Parameter:
7242 . value - The label value for this point, or -1 if the point is not in the label
7243 
7244   Level: beginner
7245 
7246 .seealso: DMLabelGetValue(), DMSetLabelValue(), DMGetStratumIS()
7247 @*/
7248 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value)
7249 {
7250   DMLabel        label;
7251   PetscErrorCode ierr;
7252 
7253   PetscFunctionBegin;
7254   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7255   PetscValidCharPointer(name, 2);
7256   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7257   if (!label) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name);
7258   ierr = DMLabelGetValue(label, point, value);CHKERRQ(ierr);
7259   PetscFunctionReturn(0);
7260 }
7261 
7262 /*@C
7263   DMSetLabelValue - Add a point to a Sieve Label with given value
7264 
7265   Not Collective
7266 
7267   Input Parameters:
7268 + dm   - The DM object
7269 . name - The label name
7270 . point - The mesh point
7271 - value - The label value for this point
7272 
7273   Output Parameter:
7274 
7275   Level: beginner
7276 
7277 .seealso: DMLabelSetValue(), DMGetStratumIS(), DMClearLabelValue()
7278 @*/
7279 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7280 {
7281   DMLabel        label;
7282   PetscErrorCode ierr;
7283 
7284   PetscFunctionBegin;
7285   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7286   PetscValidCharPointer(name, 2);
7287   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7288   if (!label) {
7289     ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
7290     ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7291   }
7292   ierr = DMLabelSetValue(label, point, value);CHKERRQ(ierr);
7293   PetscFunctionReturn(0);
7294 }
7295 
7296 /*@C
7297   DMClearLabelValue - Remove a point from a Sieve Label with given value
7298 
7299   Not Collective
7300 
7301   Input Parameters:
7302 + dm   - The DM object
7303 . name - The label name
7304 . point - The mesh point
7305 - value - The label value for this point
7306 
7307   Output Parameter:
7308 
7309   Level: beginner
7310 
7311 .seealso: DMLabelClearValue(), DMSetLabelValue(), DMGetStratumIS()
7312 @*/
7313 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value)
7314 {
7315   DMLabel        label;
7316   PetscErrorCode ierr;
7317 
7318   PetscFunctionBegin;
7319   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7320   PetscValidCharPointer(name, 2);
7321   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7322   if (!label) PetscFunctionReturn(0);
7323   ierr = DMLabelClearValue(label, point, value);CHKERRQ(ierr);
7324   PetscFunctionReturn(0);
7325 }
7326 
7327 /*@C
7328   DMGetLabelSize - Get the number of different integer ids in a Label
7329 
7330   Not Collective
7331 
7332   Input Parameters:
7333 + dm   - The DM object
7334 - name - The label name
7335 
7336   Output Parameter:
7337 . size - The number of different integer ids, or 0 if the label does not exist
7338 
7339   Level: beginner
7340 
7341 .seealso: DMLabelGetNumValues(), DMSetLabelValue()
7342 @*/
7343 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size)
7344 {
7345   DMLabel        label;
7346   PetscErrorCode ierr;
7347 
7348   PetscFunctionBegin;
7349   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7350   PetscValidCharPointer(name, 2);
7351   PetscValidIntPointer(size, 3);
7352   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7353   *size = 0;
7354   if (!label) PetscFunctionReturn(0);
7355   ierr = DMLabelGetNumValues(label, size);CHKERRQ(ierr);
7356   PetscFunctionReturn(0);
7357 }
7358 
7359 /*@C
7360   DMGetLabelIdIS - Get the integer ids in a label
7361 
7362   Not Collective
7363 
7364   Input Parameters:
7365 + mesh - The DM object
7366 - name - The label name
7367 
7368   Output Parameter:
7369 . ids - The integer ids, or NULL if the label does not exist
7370 
7371   Level: beginner
7372 
7373 .seealso: DMLabelGetValueIS(), DMGetLabelSize()
7374 @*/
7375 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids)
7376 {
7377   DMLabel        label;
7378   PetscErrorCode ierr;
7379 
7380   PetscFunctionBegin;
7381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7382   PetscValidCharPointer(name, 2);
7383   PetscValidPointer(ids, 3);
7384   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7385   *ids = NULL;
7386  if (label) {
7387     ierr = DMLabelGetValueIS(label, ids);CHKERRQ(ierr);
7388   } else {
7389     /* returning an empty IS */
7390     ierr = ISCreateGeneral(PETSC_COMM_SELF,0,NULL,PETSC_USE_POINTER,ids);CHKERRQ(ierr);
7391   }
7392   PetscFunctionReturn(0);
7393 }
7394 
7395 /*@C
7396   DMGetStratumSize - Get the number of points in a label stratum
7397 
7398   Not Collective
7399 
7400   Input Parameters:
7401 + dm - The DM object
7402 . name - The label name
7403 - value - The stratum value
7404 
7405   Output Parameter:
7406 . size - The stratum size
7407 
7408   Level: beginner
7409 
7410 .seealso: DMLabelGetStratumSize(), DMGetLabelSize(), DMGetLabelIds()
7411 @*/
7412 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size)
7413 {
7414   DMLabel        label;
7415   PetscErrorCode ierr;
7416 
7417   PetscFunctionBegin;
7418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7419   PetscValidCharPointer(name, 2);
7420   PetscValidIntPointer(size, 4);
7421   ierr  = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7422   *size = 0;
7423   if (!label) PetscFunctionReturn(0);
7424   ierr = DMLabelGetStratumSize(label, value, size);CHKERRQ(ierr);
7425   PetscFunctionReturn(0);
7426 }
7427 
7428 /*@C
7429   DMGetStratumIS - Get the points in a label stratum
7430 
7431   Not Collective
7432 
7433   Input Parameters:
7434 + dm - The DM object
7435 . name - The label name
7436 - value - The stratum value
7437 
7438   Output Parameter:
7439 . points - The stratum points, or NULL if the label does not exist or does not have that value
7440 
7441   Level: beginner
7442 
7443 .seealso: DMLabelGetStratumIS(), DMGetStratumSize()
7444 @*/
7445 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points)
7446 {
7447   DMLabel        label;
7448   PetscErrorCode ierr;
7449 
7450   PetscFunctionBegin;
7451   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7452   PetscValidCharPointer(name, 2);
7453   PetscValidPointer(points, 4);
7454   ierr    = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7455   *points = NULL;
7456   if (!label) PetscFunctionReturn(0);
7457   ierr = DMLabelGetStratumIS(label, value, points);CHKERRQ(ierr);
7458   PetscFunctionReturn(0);
7459 }
7460 
7461 /*@C
7462   DMSetStratumIS - Set the points in a label stratum
7463 
7464   Not Collective
7465 
7466   Input Parameters:
7467 + dm - The DM object
7468 . name - The label name
7469 . value - The stratum value
7470 - points - The stratum points
7471 
7472   Level: beginner
7473 
7474 .seealso: DMLabelSetStratumIS(), DMGetStratumSize()
7475 @*/
7476 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points)
7477 {
7478   DMLabel        label;
7479   PetscErrorCode ierr;
7480 
7481   PetscFunctionBegin;
7482   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7483   PetscValidCharPointer(name, 2);
7484   PetscValidPointer(points, 4);
7485   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7486   if (!label) PetscFunctionReturn(0);
7487   ierr = DMLabelSetStratumIS(label, value, points);CHKERRQ(ierr);
7488   PetscFunctionReturn(0);
7489 }
7490 
7491 /*@C
7492   DMClearLabelStratum - Remove all points from a stratum from a Sieve Label
7493 
7494   Not Collective
7495 
7496   Input Parameters:
7497 + dm   - The DM object
7498 . name - The label name
7499 - value - The label value for this point
7500 
7501   Output Parameter:
7502 
7503   Level: beginner
7504 
7505 .seealso: DMLabelClearStratum(), DMSetLabelValue(), DMGetStratumIS(), DMClearLabelValue()
7506 @*/
7507 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value)
7508 {
7509   DMLabel        label;
7510   PetscErrorCode ierr;
7511 
7512   PetscFunctionBegin;
7513   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7514   PetscValidCharPointer(name, 2);
7515   ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
7516   if (!label) PetscFunctionReturn(0);
7517   ierr = DMLabelClearStratum(label, value);CHKERRQ(ierr);
7518   PetscFunctionReturn(0);
7519 }
7520 
7521 /*@
7522   DMGetNumLabels - Return the number of labels defined by the mesh
7523 
7524   Not Collective
7525 
7526   Input Parameter:
7527 . dm   - The DM object
7528 
7529   Output Parameter:
7530 . numLabels - the number of Labels
7531 
7532   Level: intermediate
7533 
7534 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7535 @*/
7536 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels)
7537 {
7538   DMLabelLink next = dm->labels;
7539   PetscInt  n    = 0;
7540 
7541   PetscFunctionBegin;
7542   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7543   PetscValidIntPointer(numLabels, 2);
7544   while (next) {++n; next = next->next;}
7545   *numLabels = n;
7546   PetscFunctionReturn(0);
7547 }
7548 
7549 /*@C
7550   DMGetLabelName - Return the name of nth label
7551 
7552   Not Collective
7553 
7554   Input Parameters:
7555 + dm - The DM object
7556 - n  - the label number
7557 
7558   Output Parameter:
7559 . name - the label name
7560 
7561   Level: intermediate
7562 
7563 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7564 @*/
7565 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name)
7566 {
7567   DMLabelLink    next = dm->labels;
7568   PetscInt       l    = 0;
7569   PetscErrorCode ierr;
7570 
7571   PetscFunctionBegin;
7572   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7573   PetscValidPointer(name, 3);
7574   while (next) {
7575     if (l == n) {
7576       ierr = PetscObjectGetName((PetscObject) next->label, name);CHKERRQ(ierr);
7577       PetscFunctionReturn(0);
7578     }
7579     ++l;
7580     next = next->next;
7581   }
7582   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7583 }
7584 
7585 /*@C
7586   DMHasLabel - Determine whether the mesh has a label of a given name
7587 
7588   Not Collective
7589 
7590   Input Parameters:
7591 + dm   - The DM object
7592 - name - The label name
7593 
7594   Output Parameter:
7595 . hasLabel - PETSC_TRUE if the label is present
7596 
7597   Level: intermediate
7598 
7599 .seealso: DMCreateLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7600 @*/
7601 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel)
7602 {
7603   DMLabelLink    next = dm->labels;
7604   const char    *lname;
7605   PetscErrorCode ierr;
7606 
7607   PetscFunctionBegin;
7608   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7609   PetscValidCharPointer(name, 2);
7610   PetscValidBoolPointer(hasLabel, 3);
7611   *hasLabel = PETSC_FALSE;
7612   while (next) {
7613     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7614     ierr = PetscStrcmp(name, lname, hasLabel);CHKERRQ(ierr);
7615     if (*hasLabel) break;
7616     next = next->next;
7617   }
7618   PetscFunctionReturn(0);
7619 }
7620 
7621 /*@C
7622   DMGetLabel - Return the label of a given name, or NULL
7623 
7624   Not Collective
7625 
7626   Input Parameters:
7627 + dm   - The DM object
7628 - name - The label name
7629 
7630   Output Parameter:
7631 . label - The DMLabel, or NULL if the label is absent
7632 
7633   Level: intermediate
7634 
7635 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7636 @*/
7637 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label)
7638 {
7639   DMLabelLink    next = dm->labels;
7640   PetscBool      hasLabel;
7641   const char    *lname;
7642   PetscErrorCode ierr;
7643 
7644   PetscFunctionBegin;
7645   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7646   PetscValidCharPointer(name, 2);
7647   PetscValidPointer(label, 3);
7648   *label = NULL;
7649   while (next) {
7650     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7651     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7652     if (hasLabel) {
7653       *label = next->label;
7654       break;
7655     }
7656     next = next->next;
7657   }
7658   PetscFunctionReturn(0);
7659 }
7660 
7661 /*@C
7662   DMGetLabelByNum - Return the nth label
7663 
7664   Not Collective
7665 
7666   Input Parameters:
7667 + dm - The DM object
7668 - n  - the label number
7669 
7670   Output Parameter:
7671 . label - the label
7672 
7673   Level: intermediate
7674 
7675 .seealso: DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7676 @*/
7677 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label)
7678 {
7679   DMLabelLink next = dm->labels;
7680   PetscInt    l    = 0;
7681 
7682   PetscFunctionBegin;
7683   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7684   PetscValidPointer(label, 3);
7685   while (next) {
7686     if (l == n) {
7687       *label = next->label;
7688       PetscFunctionReturn(0);
7689     }
7690     ++l;
7691     next = next->next;
7692   }
7693   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %D does not exist in this DM", n);
7694 }
7695 
7696 /*@C
7697   DMAddLabel - Add the label to this mesh
7698 
7699   Not Collective
7700 
7701   Input Parameters:
7702 + dm   - The DM object
7703 - label - The DMLabel
7704 
7705   Level: developer
7706 
7707 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7708 @*/
7709 PetscErrorCode DMAddLabel(DM dm, DMLabel label)
7710 {
7711   DMLabelLink    l, *p, tmpLabel;
7712   PetscBool      hasLabel;
7713   const char    *lname;
7714   PetscBool      flg;
7715   PetscErrorCode ierr;
7716 
7717   PetscFunctionBegin;
7718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7719   ierr = PetscObjectGetName((PetscObject) label, &lname);CHKERRQ(ierr);
7720   ierr = DMHasLabel(dm, lname, &hasLabel);CHKERRQ(ierr);
7721   if (hasLabel) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname);
7722   ierr = PetscCalloc1(1, &tmpLabel);CHKERRQ(ierr);
7723   tmpLabel->label  = label;
7724   tmpLabel->output = PETSC_TRUE;
7725   for (p=&dm->labels; (l=*p); p=&l->next) {}
7726   *p = tmpLabel;
7727   ierr = PetscObjectReference((PetscObject)label);CHKERRQ(ierr);
7728   ierr = PetscStrcmp(lname, "depth", &flg);CHKERRQ(ierr);
7729   if (flg) dm->depthLabel = label;
7730   ierr = PetscStrcmp(lname, "celltype", &flg);CHKERRQ(ierr);
7731   if (flg) dm->celltypeLabel = label;
7732   PetscFunctionReturn(0);
7733 }
7734 
7735 /*@C
7736   DMRemoveLabel - Remove the label given by name from this mesh
7737 
7738   Not Collective
7739 
7740   Input Parameters:
7741 + dm   - The DM object
7742 - name - The label name
7743 
7744   Output Parameter:
7745 . label - The DMLabel, or NULL if the label is absent
7746 
7747   Level: developer
7748 
7749   Notes:
7750   DMRemoveLabel(dm,name,NULL) removes the label from dm and calls
7751   DMLabelDestroy() on the label.
7752 
7753   DMRemoveLabel(dm,name,&label) removes the label from dm, but it DOES NOT
7754   call DMLabelDestroy(). Instead, the label is returned and the user is
7755   responsible of calling DMLabelDestroy() at some point.
7756 
7757 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel(), DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabelBySelf()
7758 @*/
7759 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label)
7760 {
7761   DMLabelLink    link, *pnext;
7762   PetscBool      hasLabel;
7763   const char    *lname;
7764   PetscErrorCode ierr;
7765 
7766   PetscFunctionBegin;
7767   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7768   PetscValidCharPointer(name, 2);
7769   if (label) {
7770     PetscValidPointer(label, 3);
7771     *label = NULL;
7772   }
7773   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7774     ierr = PetscObjectGetName((PetscObject) link->label, &lname);CHKERRQ(ierr);
7775     ierr = PetscStrcmp(name, lname, &hasLabel);CHKERRQ(ierr);
7776     if (hasLabel) {
7777       *pnext = link->next; /* Remove from list */
7778       ierr = PetscStrcmp(name, "depth", &hasLabel);CHKERRQ(ierr);
7779       if (hasLabel) dm->depthLabel = NULL;
7780       ierr = PetscStrcmp(name, "celltype", &hasLabel);CHKERRQ(ierr);
7781       if (hasLabel) dm->celltypeLabel = NULL;
7782       if (label) *label = link->label;
7783       else       {ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);}
7784       ierr = PetscFree(link);CHKERRQ(ierr);
7785       break;
7786     }
7787   }
7788   PetscFunctionReturn(0);
7789 }
7790 
7791 /*@
7792   DMRemoveLabelBySelf - Remove the label from this mesh
7793 
7794   Not Collective
7795 
7796   Input Parameters:
7797 + dm   - The DM object
7798 . label - (Optional) The DMLabel to be removed from the DM
7799 - failNotFound - Should it fail if the label is not found in the DM?
7800 
7801   Level: developer
7802 
7803   Notes:
7804   Only exactly the same instance is removed if found, name match is ignored.
7805   If the DM has an exclusive reference to the label, it gets destroyed and
7806   *label nullified.
7807 
7808 .seealso: DMCreateLabel(), DMHasLabel(), DMGetLabel() DMGetLabelValue(), DMSetLabelValue(), DMLabelDestroy(), DMRemoveLabel()
7809 @*/
7810 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound)
7811 {
7812   DMLabelLink    link, *pnext;
7813   PetscBool      hasLabel = PETSC_FALSE;
7814   PetscErrorCode ierr;
7815 
7816   PetscFunctionBegin;
7817   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7818   PetscValidPointer(label, 2);
7819   if (!*label && !failNotFound) PetscFunctionReturn(0);
7820   PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2);
7821   PetscValidLogicalCollectiveBool(dm,failNotFound,3);
7822   for (pnext=&dm->labels; (link=*pnext); pnext=&link->next) {
7823     if (*label == link->label) {
7824       hasLabel = PETSC_TRUE;
7825       *pnext = link->next; /* Remove from list */
7826       if (*label == dm->depthLabel) dm->depthLabel = NULL;
7827       if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL;
7828       if (((PetscObject) link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */
7829       ierr = DMLabelDestroy(&link->label);CHKERRQ(ierr);
7830       ierr = PetscFree(link);CHKERRQ(ierr);
7831       break;
7832     }
7833   }
7834   if (!hasLabel && failNotFound) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM");
7835   PetscFunctionReturn(0);
7836 }
7837 
7838 /*@C
7839   DMGetLabelOutput - Get the output flag for a given label
7840 
7841   Not Collective
7842 
7843   Input Parameters:
7844 + dm   - The DM object
7845 - name - The label name
7846 
7847   Output Parameter:
7848 . output - The flag for output
7849 
7850   Level: developer
7851 
7852 .seealso: DMSetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7853 @*/
7854 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output)
7855 {
7856   DMLabelLink    next = dm->labels;
7857   const char    *lname;
7858   PetscErrorCode ierr;
7859 
7860   PetscFunctionBegin;
7861   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7862   PetscValidPointer(name, 2);
7863   PetscValidPointer(output, 3);
7864   while (next) {
7865     PetscBool flg;
7866 
7867     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7868     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7869     if (flg) {*output = next->output; PetscFunctionReturn(0);}
7870     next = next->next;
7871   }
7872   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7873 }
7874 
7875 /*@C
7876   DMSetLabelOutput - Set the output flag for a given label
7877 
7878   Not Collective
7879 
7880   Input Parameters:
7881 + dm     - The DM object
7882 . name   - The label name
7883 - output - The flag for output
7884 
7885   Level: developer
7886 
7887 .seealso: DMGetLabelOutput(), DMCreateLabel(), DMHasLabel(), DMGetLabelValue(), DMSetLabelValue(), DMGetStratumIS()
7888 @*/
7889 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output)
7890 {
7891   DMLabelLink    next = dm->labels;
7892   const char    *lname;
7893   PetscErrorCode ierr;
7894 
7895   PetscFunctionBegin;
7896   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7897   PetscValidCharPointer(name, 2);
7898   while (next) {
7899     PetscBool flg;
7900 
7901     ierr = PetscObjectGetName((PetscObject) next->label, &lname);CHKERRQ(ierr);
7902     ierr = PetscStrcmp(name, lname, &flg);CHKERRQ(ierr);
7903     if (flg) {next->output = output; PetscFunctionReturn(0);}
7904     next = next->next;
7905   }
7906   SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name);
7907 }
7908 
7909 /*@
7910   DMCopyLabels - Copy labels from one mesh to another with a superset of the points
7911 
7912   Collective on dmA
7913 
7914   Input Parameter:
7915 + dmA - The DM object with initial labels
7916 . dmB - The DM object with copied labels
7917 . mode - Copy labels by pointers (PETSC_OWN_POINTER) or duplicate them (PETSC_COPY_VALUES)
7918 - all  - Copy all labels including "depth", "dim", and "celltype" (PETSC_TRUE) which are otherwise ignored (PETSC_FALSE)
7919 
7920   Level: intermediate
7921 
7922   Note: This is typically used when interpolating or otherwise adding to a mesh
7923 
7924 .seealso: DMGetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM(), DMGetCoordinateSection(), DMShareLabels()
7925 @*/
7926 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all)
7927 {
7928   DMLabel        label, labelNew;
7929   const char    *name;
7930   PetscBool      flg;
7931   DMLabelLink    link;
7932   PetscErrorCode ierr;
7933 
7934   PetscFunctionBegin;
7935   PetscValidHeaderSpecific(dmA, DM_CLASSID, 1);
7936   PetscValidHeaderSpecific(dmB, DM_CLASSID, 2);
7937   PetscValidLogicalCollectiveEnum(dmA, mode,3);
7938   PetscValidLogicalCollectiveBool(dmA, all, 4);
7939   if (mode==PETSC_USE_POINTER) SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects");
7940   if (dmA == dmB) PetscFunctionReturn(0);
7941   for (link=dmA->labels; link; link=link->next) {
7942     label=link->label;
7943     ierr = PetscObjectGetName((PetscObject)label, &name);CHKERRQ(ierr);
7944     if (!all) {
7945       ierr = PetscStrcmp(name, "depth", &flg);CHKERRQ(ierr);
7946       if (flg) continue;
7947       ierr = PetscStrcmp(name, "dim", &flg);CHKERRQ(ierr);
7948       if (flg) continue;
7949       ierr = PetscStrcmp(name, "celltype", &flg);CHKERRQ(ierr);
7950       if (flg) continue;
7951     }
7952     if (mode==PETSC_COPY_VALUES) {
7953       ierr = DMLabelDuplicate(label, &labelNew);CHKERRQ(ierr);
7954     } else {
7955       labelNew = label;
7956     }
7957     ierr = DMAddLabel(dmB, labelNew);CHKERRQ(ierr);
7958     if (mode==PETSC_COPY_VALUES) {ierr = DMLabelDestroy(&labelNew);CHKERRQ(ierr);}
7959   }
7960   PetscFunctionReturn(0);
7961 }
7962 /*
7963   Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would
7964   like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every
7965   (label, id) pair in the DM.
7966 
7967   However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to
7968   each label.
7969 */
7970 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal)
7971 {
7972   DMUniversalLabel ul;
7973   PetscBool       *active;
7974   PetscInt         pStart, pEnd, p, Nl, l, m;
7975   PetscErrorCode   ierr;
7976 
7977   PetscFunctionBegin;
7978   ierr = PetscMalloc1(1, &ul);CHKERRQ(ierr);
7979   ierr = DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label);CHKERRQ(ierr);
7980   ierr = DMGetNumLabels(dm, &Nl);CHKERRQ(ierr);
7981   ierr = PetscCalloc1(Nl, &active);CHKERRQ(ierr);
7982   ul->Nl = 0;
7983   for (l = 0; l < Nl; ++l) {
7984     PetscBool   isdepth, iscelltype;
7985     const char *name;
7986 
7987     ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
7988     ierr = PetscStrncmp(name, "depth", 6, &isdepth);CHKERRQ(ierr);
7989     ierr = PetscStrncmp(name, "celltype", 9, &iscelltype);CHKERRQ(ierr);
7990     active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE;
7991     if (active[l]) ++ul->Nl;
7992   }
7993   ierr = PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl+1, &ul->offsets, ul->Nl+1, &ul->bits, ul->Nl, &ul->masks);CHKERRQ(ierr);
7994   ul->Nv = 0;
7995   for (l = 0, m = 0; l < Nl; ++l) {
7996     DMLabel     label;
7997     PetscInt    nv;
7998     const char *name;
7999 
8000     if (!active[l]) continue;
8001     ierr = DMGetLabelName(dm, l, &name);CHKERRQ(ierr);
8002     ierr = DMGetLabelByNum(dm, l, &label);CHKERRQ(ierr);
8003     ierr = DMLabelGetNumValues(label, &nv);CHKERRQ(ierr);
8004     ierr = PetscStrallocpy(name, &ul->names[m]);CHKERRQ(ierr);
8005     ul->indices[m]   = l;
8006     ul->Nv          += nv;
8007     ul->offsets[m+1] = nv;
8008     ul->bits[m+1]    = PetscCeilReal(PetscLog2Real(nv+1));
8009     ++m;
8010   }
8011   for (l = 1; l <= ul->Nl; ++l) {
8012     ul->offsets[l] = ul->offsets[l-1] + ul->offsets[l];
8013     ul->bits[l]    = ul->bits[l-1]    + ul->bits[l];
8014   }
8015   for (l = 0; l < ul->Nl; ++l) {
8016     PetscInt b;
8017 
8018     ul->masks[l] = 0;
8019     for (b = ul->bits[l]; b < ul->bits[l+1]; ++b) ul->masks[l] |= 1 << b;
8020   }
8021   ierr = PetscMalloc1(ul->Nv, &ul->values);CHKERRQ(ierr);
8022   for (l = 0, m = 0; l < Nl; ++l) {
8023     DMLabel         label;
8024     IS              valueIS;
8025     const PetscInt *varr;
8026     PetscInt        nv, v;
8027 
8028     if (!active[l]) continue;
8029     ierr = DMGetLabelByNum(dm, l, &label);CHKERRQ(ierr);
8030     ierr = DMLabelGetNumValues(label, &nv);CHKERRQ(ierr);
8031     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
8032     ierr = ISGetIndices(valueIS, &varr);CHKERRQ(ierr);
8033     for (v = 0; v < nv; ++v) {
8034       ul->values[ul->offsets[m]+v] = varr[v];
8035     }
8036     ierr = ISRestoreIndices(valueIS, &varr);CHKERRQ(ierr);
8037     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
8038     ierr = PetscSortInt(nv, &ul->values[ul->offsets[m]]);CHKERRQ(ierr);
8039     ++m;
8040   }
8041   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8042   for (p = pStart; p < pEnd; ++p) {
8043     PetscInt  uval = 0;
8044     PetscBool marked = PETSC_FALSE;
8045 
8046     for (l = 0, m = 0; l < Nl; ++l) {
8047       DMLabel  label;
8048       PetscInt val, defval, loc, nv;
8049 
8050       if (!active[l]) continue;
8051       ierr = DMGetLabelByNum(dm, l, &label);CHKERRQ(ierr);
8052       ierr = DMLabelGetValue(label, p, &val);CHKERRQ(ierr);
8053       ierr = DMLabelGetDefaultValue(label, &defval);CHKERRQ(ierr);
8054       if (val == defval) {++m; continue;}
8055       nv = ul->offsets[m+1]-ul->offsets[m];
8056       marked = PETSC_TRUE;
8057       ierr = PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc);CHKERRQ(ierr);
8058       if (loc < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %D not found in compression array", val);
8059       uval += (loc+1) << ul->bits[m];
8060       ++m;
8061     }
8062     if (marked) {ierr = DMLabelSetValue(ul->label, p, uval);CHKERRQ(ierr);}
8063   }
8064   ierr = PetscFree(active);CHKERRQ(ierr);
8065   *universal = ul;
8066   PetscFunctionReturn(0);
8067 }
8068 
8069 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal)
8070 {
8071   PetscInt       l;
8072   PetscErrorCode ierr;
8073 
8074   PetscFunctionBegin;
8075   for (l = 0; l < (*universal)->Nl; ++l) {ierr = PetscFree((*universal)->names[l]);CHKERRQ(ierr);}
8076   ierr = DMLabelDestroy(&(*universal)->label);CHKERRQ(ierr);
8077   ierr = PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks);CHKERRQ(ierr);
8078   ierr = PetscFree((*universal)->values);CHKERRQ(ierr);
8079   ierr = PetscFree(*universal);CHKERRQ(ierr);
8080   *universal = NULL;
8081   PetscFunctionReturn(0);
8082 }
8083 
8084 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel)
8085 {
8086   PetscFunctionBegin;
8087   PetscValidPointer(ulabel, 2);
8088   *ulabel = ul->label;
8089   PetscFunctionReturn(0);
8090 }
8091 
8092 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm)
8093 {
8094   PetscInt       Nl = ul->Nl, l;
8095   PetscErrorCode ierr;
8096 
8097   PetscFunctionBegin;
8098   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
8099   for (l = 0; l < Nl; ++l) {
8100     if (preserveOrder) {ierr = DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l]);CHKERRQ(ierr);}
8101     else               {ierr = DMCreateLabel(dm, ul->names[l]);CHKERRQ(ierr);}
8102   }
8103   if (preserveOrder) {
8104     for (l = 0; l < ul->Nl; ++l) {
8105       const char *name;
8106       PetscBool   match;
8107 
8108       ierr = DMGetLabelName(dm, ul->indices[l], &name);CHKERRQ(ierr);
8109       ierr = PetscStrcmp(name, ul->names[l], &match);CHKERRQ(ierr);
8110       if (!match) SETERRQ3(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Label %D name %s does not match new name %s", l, name, ul->names[l]);
8111     }
8112   }
8113   PetscFunctionReturn(0);
8114 }
8115 
8116 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value)
8117 {
8118   PetscInt       l;
8119   PetscErrorCode ierr;
8120 
8121   PetscFunctionBegin;
8122   for (l = 0; l < ul->Nl; ++l) {
8123     DMLabel  label;
8124     PetscInt lval = (value & ul->masks[l]) >> ul->bits[l];
8125 
8126     if (lval) {
8127       if (useIndex) {ierr = DMGetLabelByNum(dm, ul->indices[l], &label);CHKERRQ(ierr);}
8128       else          {ierr = DMGetLabel(dm, ul->names[l], &label);CHKERRQ(ierr);}
8129       ierr = DMLabelSetValue(label, p, ul->values[ul->offsets[l]+lval-1]);CHKERRQ(ierr);
8130     }
8131   }
8132   PetscFunctionReturn(0);
8133 }
8134 
8135 /*@
8136   DMGetCoarseDM - Get the coarse mesh from which this was obtained by refinement
8137 
8138   Input Parameter:
8139 . dm - The DM object
8140 
8141   Output Parameter:
8142 . cdm - The coarse DM
8143 
8144   Level: intermediate
8145 
8146 .seealso: DMSetCoarseDM()
8147 @*/
8148 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm)
8149 {
8150   PetscFunctionBegin;
8151   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8152   PetscValidPointer(cdm, 2);
8153   *cdm = dm->coarseMesh;
8154   PetscFunctionReturn(0);
8155 }
8156 
8157 /*@
8158   DMSetCoarseDM - Set the coarse mesh from which this was obtained by refinement
8159 
8160   Input Parameters:
8161 + dm - The DM object
8162 - cdm - The coarse DM
8163 
8164   Level: intermediate
8165 
8166 .seealso: DMGetCoarseDM()
8167 @*/
8168 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm)
8169 {
8170   PetscErrorCode ierr;
8171 
8172   PetscFunctionBegin;
8173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8174   if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2);
8175   ierr = PetscObjectReference((PetscObject)cdm);CHKERRQ(ierr);
8176   ierr = DMDestroy(&dm->coarseMesh);CHKERRQ(ierr);
8177   dm->coarseMesh = cdm;
8178   PetscFunctionReturn(0);
8179 }
8180 
8181 /*@
8182   DMGetFineDM - Get the fine mesh from which this was obtained by refinement
8183 
8184   Input Parameter:
8185 . dm - The DM object
8186 
8187   Output Parameter:
8188 . fdm - The fine DM
8189 
8190   Level: intermediate
8191 
8192 .seealso: DMSetFineDM()
8193 @*/
8194 PetscErrorCode DMGetFineDM(DM dm, DM *fdm)
8195 {
8196   PetscFunctionBegin;
8197   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8198   PetscValidPointer(fdm, 2);
8199   *fdm = dm->fineMesh;
8200   PetscFunctionReturn(0);
8201 }
8202 
8203 /*@
8204   DMSetFineDM - Set the fine mesh from which this was obtained by refinement
8205 
8206   Input Parameters:
8207 + dm - The DM object
8208 - fdm - The fine DM
8209 
8210   Level: intermediate
8211 
8212 .seealso: DMGetFineDM()
8213 @*/
8214 PetscErrorCode DMSetFineDM(DM dm, DM fdm)
8215 {
8216   PetscErrorCode ierr;
8217 
8218   PetscFunctionBegin;
8219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8220   if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2);
8221   ierr = PetscObjectReference((PetscObject)fdm);CHKERRQ(ierr);
8222   ierr = DMDestroy(&dm->fineMesh);CHKERRQ(ierr);
8223   dm->fineMesh = fdm;
8224   PetscFunctionReturn(0);
8225 }
8226 
8227 /*=== DMBoundary code ===*/
8228 
8229 PetscErrorCode DMCopyBoundary(DM dm, DM dmNew)
8230 {
8231   PetscInt       d;
8232   PetscErrorCode ierr;
8233 
8234   PetscFunctionBegin;
8235   for (d = 0; d < dm->Nds; ++d) {
8236     ierr = PetscDSCopyBoundary(dm->probs[d].ds, dmNew->probs[d].ds);CHKERRQ(ierr);
8237   }
8238   PetscFunctionReturn(0);
8239 }
8240 
8241 /*@C
8242   DMAddBoundary - Add a boundary condition to the model
8243 
8244   Collective on dm
8245 
8246   Input Parameters:
8247 + dm          - The DM, with a PetscDS that matches the problem being constrained
8248 . type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8249 . name        - The BC name
8250 . labelname   - The label defining constrained points
8251 . field       - The field to constrain
8252 . numcomps    - The number of constrained field components (0 will constrain all fields)
8253 . comps       - An array of constrained component numbers
8254 . bcFunc      - A pointwise function giving boundary values
8255 . bcFunc_t    - A pointwise function giving the time deriative of the boundary values, or NULL
8256 . numids      - The number of DMLabel ids for constrained points
8257 . ids         - An array of ids for constrained points
8258 - ctx         - An optional user context for bcFunc
8259 
8260   Options Database Keys:
8261 + -bc_<boundary name> <num> - Overrides the boundary ids
8262 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8263 
8264   Note:
8265   Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if DM_BC_ESSENTIAL, Then the calling sequence is:
8266 
8267 $ bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[])
8268 
8269   If the type is DM_BC_ESSENTIAL_FIELD or other _FIELD value, then the calling sequence is:
8270 
8271 $ bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8272 $        const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8273 $        const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8274 $        PetscReal time, const PetscReal x[], PetscScalar bcval[])
8275 
8276 + dim - the spatial dimension
8277 . Nf - the number of fields
8278 . uOff - the offset into u[] and u_t[] for each field
8279 . uOff_x - the offset into u_x[] for each field
8280 . u - each field evaluated at the current point
8281 . u_t - the time derivative of each field evaluated at the current point
8282 . u_x - the gradient of each field evaluated at the current point
8283 . aOff - the offset into a[] and a_t[] for each auxiliary field
8284 . aOff_x - the offset into a_x[] for each auxiliary field
8285 . a - each auxiliary field evaluated at the current point
8286 . a_t - the time derivative of each auxiliary field evaluated at the current point
8287 . a_x - the gradient of auxiliary each field evaluated at the current point
8288 . t - current time
8289 . x - coordinates of the current point
8290 . numConstants - number of constant parameters
8291 . constants - constant parameters
8292 - bcval - output values at the current point
8293 
8294   Level: developer
8295 
8296 .seealso: DMGetBoundary(), PetscDSAddBoundary()
8297 @*/
8298 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)
8299 {
8300   PetscDS        ds;
8301   PetscErrorCode ierr;
8302 
8303   PetscFunctionBegin;
8304   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8305   PetscValidLogicalCollectiveEnum(dm, type, 2);
8306   PetscValidLogicalCollectiveInt(dm, field, 5);
8307   PetscValidLogicalCollectiveInt(dm, numcomps, 6);
8308   PetscValidLogicalCollectiveInt(dm, numids, 9);
8309   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
8310   ierr = DMCompleteBoundaryLabel_Internal(dm, ds, field, PETSC_MAX_INT, labelname);CHKERRQ(ierr);
8311   ierr = PetscDSAddBoundary(ds, type,name, labelname, field, numcomps, comps, bcFunc, bcFunc_t, numids, ids, ctx);CHKERRQ(ierr);
8312   PetscFunctionReturn(0);
8313 }
8314 
8315 /*@
8316   DMGetNumBoundary - Get the number of registered BC
8317 
8318   Input Parameters:
8319 . dm - The mesh object
8320 
8321   Output Parameters:
8322 . numBd - The number of BC
8323 
8324   Level: intermediate
8325 
8326 .seealso: DMAddBoundary(), DMGetBoundary()
8327 @*/
8328 PetscErrorCode DMGetNumBoundary(DM dm, PetscInt *numBd)
8329 {
8330   PetscDS        ds;
8331   PetscErrorCode ierr;
8332 
8333   PetscFunctionBegin;
8334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8335   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
8336   ierr = PetscDSGetNumBoundary(ds, numBd);CHKERRQ(ierr);
8337   PetscFunctionReturn(0);
8338 }
8339 
8340 /*@C
8341   DMGetBoundary - Get a model boundary condition
8342 
8343   Input Parameters:
8344 + dm          - The mesh object
8345 - bd          - The BC number
8346 
8347   Output Parameters:
8348 + type        - The type of condition, e.g. DM_BC_ESSENTIAL_ANALYTIC/DM_BC_ESSENTIAL_FIELD (Dirichlet), or DM_BC_NATURAL (Neumann)
8349 . name        - The BC name
8350 . labelname   - The label defining constrained points
8351 . field       - The field to constrain
8352 . numcomps    - The number of constrained field components
8353 . comps       - An array of constrained component numbers
8354 . bcFunc      - A pointwise function giving boundary values
8355 . bcFunc_t    - A pointwise function giving the time derviative of the boundary values
8356 . numids      - The number of DMLabel ids for constrained points
8357 . ids         - An array of ids for constrained points
8358 - ctx         - An optional user context for bcFunc
8359 
8360   Options Database Keys:
8361 + -bc_<boundary name> <num> - Overrides the boundary ids
8362 - -bc_<boundary name>_comp <num> - Overrides the boundary components
8363 
8364   Level: developer
8365 
8366 .seealso: DMAddBoundary()
8367 @*/
8368 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)
8369 {
8370   PetscDS        ds;
8371   PetscErrorCode ierr;
8372 
8373   PetscFunctionBegin;
8374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8375   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
8376   ierr = PetscDSGetBoundary(ds, bd, type, name, labelname, field, numcomps, comps, func, func_t, numids, ids, ctx);CHKERRQ(ierr);
8377   PetscFunctionReturn(0);
8378 }
8379 
8380 static PetscErrorCode DMPopulateBoundary(DM dm)
8381 {
8382   PetscDS        ds;
8383   DMBoundary    *lastnext;
8384   DSBoundary     dsbound;
8385   PetscErrorCode ierr;
8386 
8387   PetscFunctionBegin;
8388   ierr = DMGetDS(dm, &ds);CHKERRQ(ierr);
8389   dsbound = ds->boundary;
8390   if (dm->boundary) {
8391     DMBoundary next = dm->boundary;
8392 
8393     /* quick check to see if the PetscDS has changed */
8394     if (next->dsboundary == dsbound) PetscFunctionReturn(0);
8395     /* the PetscDS has changed: tear down and rebuild */
8396     while (next) {
8397       DMBoundary b = next;
8398 
8399       next = b->next;
8400       ierr = PetscFree(b);CHKERRQ(ierr);
8401     }
8402     dm->boundary = NULL;
8403   }
8404 
8405   lastnext = &(dm->boundary);
8406   while (dsbound) {
8407     DMBoundary dmbound;
8408 
8409     ierr = PetscNew(&dmbound);CHKERRQ(ierr);
8410     dmbound->dsboundary = dsbound;
8411     ierr = DMGetLabel(dm, dsbound->labelname, &(dmbound->label));CHKERRQ(ierr);
8412     if (!dmbound->label) {ierr = PetscInfo2(dm, "DSBoundary %s wants label %s, which is not in this dm.\n",dsbound->name,dsbound->labelname);CHKERRQ(ierr);}
8413     /* push on the back instead of the front so that it is in the same order as in the PetscDS */
8414     *lastnext = dmbound;
8415     lastnext = &(dmbound->next);
8416     dsbound = dsbound->next;
8417   }
8418   PetscFunctionReturn(0);
8419 }
8420 
8421 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd)
8422 {
8423   DMBoundary     b;
8424   PetscErrorCode ierr;
8425 
8426   PetscFunctionBegin;
8427   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8428   PetscValidBoolPointer(isBd, 3);
8429   *isBd = PETSC_FALSE;
8430   ierr = DMPopulateBoundary(dm);CHKERRQ(ierr);
8431   b = dm->boundary;
8432   while (b && !(*isBd)) {
8433     DMLabel    label = b->label;
8434     DSBoundary dsb = b->dsboundary;
8435 
8436     if (label) {
8437       PetscInt i;
8438 
8439       for (i = 0; i < dsb->numids && !(*isBd); ++i) {
8440         ierr = DMLabelStratumHasPoint(label, dsb->ids[i], point, isBd);CHKERRQ(ierr);
8441       }
8442     }
8443     b = b->next;
8444   }
8445   PetscFunctionReturn(0);
8446 }
8447 
8448 /*@C
8449   DMProjectFunction - This projects the given function into the function space provided, putting the coefficients in a global vector.
8450 
8451   Collective on DM
8452 
8453   Input Parameters:
8454 + dm      - The DM
8455 . time    - The time
8456 . funcs   - The coordinate functions to evaluate, one per field
8457 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8458 - mode    - The insertion mode for values
8459 
8460   Output Parameter:
8461 . X - vector
8462 
8463    Calling sequence of func:
8464 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8465 
8466 +  dim - The spatial dimension
8467 .  time - The time at which to sample
8468 .  x   - The coordinates
8469 .  Nf  - The number of fields
8470 .  u   - The output field values
8471 -  ctx - optional user-defined function context
8472 
8473   Level: developer
8474 
8475 .seealso: DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8476 @*/
8477 PetscErrorCode DMProjectFunction(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X)
8478 {
8479   Vec            localX;
8480   PetscErrorCode ierr;
8481 
8482   PetscFunctionBegin;
8483   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8484   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8485   ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8486   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
8487   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
8488   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8489   PetscFunctionReturn(0);
8490 }
8491 
8492 /*@C
8493   DMProjectFunctionLocal - This projects the given function into the function space provided, putting the coefficients in a local vector.
8494 
8495   Not collective
8496 
8497   Input Parameters:
8498 + dm      - The DM
8499 . time    - The time
8500 . funcs   - The coordinate functions to evaluate, one per field
8501 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8502 - mode    - The insertion mode for values
8503 
8504   Output Parameter:
8505 . localX - vector
8506 
8507    Calling sequence of func:
8508 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8509 
8510 +  dim - The spatial dimension
8511 .  x   - The coordinates
8512 .  Nf  - The number of fields
8513 .  u   - The output field values
8514 -  ctx - optional user-defined function context
8515 
8516   Level: developer
8517 
8518 .seealso: DMProjectFunction(), DMProjectFunctionLabel(), DMComputeL2Diff()
8519 @*/
8520 PetscErrorCode DMProjectFunctionLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
8521 {
8522   PetscErrorCode ierr;
8523 
8524   PetscFunctionBegin;
8525   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8526   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
8527   if (!dm->ops->projectfunctionlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLocal",((PetscObject)dm)->type_name);
8528   ierr = (dm->ops->projectfunctionlocal) (dm, time, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8529   PetscFunctionReturn(0);
8530 }
8531 
8532 /*@C
8533   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.
8534 
8535   Collective on DM
8536 
8537   Input Parameters:
8538 + dm      - The DM
8539 . time    - The time
8540 . label   - The DMLabel selecting the portion of the mesh for projection
8541 . funcs   - The coordinate functions to evaluate, one per field
8542 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8543 - mode    - The insertion mode for values
8544 
8545   Output Parameter:
8546 . X - vector
8547 
8548    Calling sequence of func:
8549 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8550 
8551 +  dim - The spatial dimension
8552 .  x   - The coordinates
8553 .  Nf  - The number of fields
8554 .  u   - The output field values
8555 -  ctx - optional user-defined function context
8556 
8557   Level: developer
8558 
8559 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal(), DMComputeL2Diff()
8560 @*/
8561 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)
8562 {
8563   Vec            localX;
8564   PetscErrorCode ierr;
8565 
8566   PetscFunctionBegin;
8567   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8568   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
8569   ierr = DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8570   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
8571   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
8572   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
8573   PetscFunctionReturn(0);
8574 }
8575 
8576 /*@C
8577   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.
8578 
8579   Not collective
8580 
8581   Input Parameters:
8582 + dm      - The DM
8583 . time    - The time
8584 . label   - The DMLabel selecting the portion of the mesh for projection
8585 . funcs   - The coordinate functions to evaluate, one per field
8586 . ctxs    - Optional array of contexts to pass to each coordinate function.  ctxs itself may be null.
8587 - mode    - The insertion mode for values
8588 
8589   Output Parameter:
8590 . localX - vector
8591 
8592    Calling sequence of func:
8593 $    func(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar u[], void *ctx);
8594 
8595 +  dim - The spatial dimension
8596 .  x   - The coordinates
8597 .  Nf  - The number of fields
8598 .  u   - The output field values
8599 -  ctx - optional user-defined function context
8600 
8601   Level: developer
8602 
8603 .seealso: DMProjectFunction(), DMProjectFunctionLocal(), DMProjectFunctionLabel(), DMComputeL2Diff()
8604 @*/
8605 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)
8606 {
8607   PetscErrorCode ierr;
8608 
8609   PetscFunctionBegin;
8610   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8611   PetscValidHeaderSpecific(localX,VEC_CLASSID,5);
8612   if (!dm->ops->projectfunctionlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFunctionLabelLocal",((PetscObject)dm)->type_name);
8613   ierr = (dm->ops->projectfunctionlabellocal) (dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX);CHKERRQ(ierr);
8614   PetscFunctionReturn(0);
8615 }
8616 
8617 /*@C
8618   DMProjectFieldLocal - This projects the given function of the input fields into the function space provided, putting the coefficients in a local vector.
8619 
8620   Not collective
8621 
8622   Input Parameters:
8623 + dm      - The DM
8624 . time    - The time
8625 . localU  - The input field vector
8626 . funcs   - The functions to evaluate, one per field
8627 - mode    - The insertion mode for values
8628 
8629   Output Parameter:
8630 . localX  - The output vector
8631 
8632    Calling sequence of func:
8633 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8634 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8635 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8636 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8637 
8638 +  dim          - The spatial dimension
8639 .  Nf           - The number of input fields
8640 .  NfAux        - The number of input auxiliary fields
8641 .  uOff         - The offset of each field in u[]
8642 .  uOff_x       - The offset of each field in u_x[]
8643 .  u            - The field values at this point in space
8644 .  u_t          - The field time derivative at this point in space (or NULL)
8645 .  u_x          - The field derivatives at this point in space
8646 .  aOff         - The offset of each auxiliary field in u[]
8647 .  aOff_x       - The offset of each auxiliary field in u_x[]
8648 .  a            - The auxiliary field values at this point in space
8649 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8650 .  a_x          - The auxiliary field derivatives at this point in space
8651 .  t            - The current time
8652 .  x            - The coordinates of this point
8653 .  numConstants - The number of constants
8654 .  constants    - The value of each constant
8655 -  f            - The value of the function at this point in space
8656 
8657   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.
8658   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
8659   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8660   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8661 
8662   Level: intermediate
8663 
8664 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8665 @*/
8666 PetscErrorCode DMProjectFieldLocal(DM dm, PetscReal time, Vec localU,
8667                                    void (**funcs)(PetscInt, PetscInt, PetscInt,
8668                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8669                                                   const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8670                                                   PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8671                                    InsertMode mode, Vec localX)
8672 {
8673   PetscErrorCode ierr;
8674 
8675   PetscFunctionBegin;
8676   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8677   PetscValidHeaderSpecific(localU,VEC_CLASSID,3);
8678   PetscValidHeaderSpecific(localX,VEC_CLASSID,6);
8679   if (!dm->ops->projectfieldlocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLocal",((PetscObject)dm)->type_name);
8680   ierr = (dm->ops->projectfieldlocal) (dm, time, localU, funcs, mode, localX);CHKERRQ(ierr);
8681   PetscFunctionReturn(0);
8682 }
8683 
8684 /*@C
8685   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.
8686 
8687   Not collective
8688 
8689   Input Parameters:
8690 + dm      - The DM
8691 . time    - The time
8692 . label   - The DMLabel marking the portion of the domain to output
8693 . numIds  - The number of label ids to use
8694 . ids     - The label ids to use for marking
8695 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8696 . comps   - The components to set in the output, or NULL for all components
8697 . localU  - The input field vector
8698 . funcs   - The functions to evaluate, one per field
8699 - mode    - The insertion mode for values
8700 
8701   Output Parameter:
8702 . localX  - The output vector
8703 
8704    Calling sequence of func:
8705 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8706 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8707 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8708 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8709 
8710 +  dim          - The spatial dimension
8711 .  Nf           - The number of input fields
8712 .  NfAux        - The number of input auxiliary fields
8713 .  uOff         - The offset of each field in u[]
8714 .  uOff_x       - The offset of each field in u_x[]
8715 .  u            - The field values at this point in space
8716 .  u_t          - The field time derivative at this point in space (or NULL)
8717 .  u_x          - The field derivatives at this point in space
8718 .  aOff         - The offset of each auxiliary field in u[]
8719 .  aOff_x       - The offset of each auxiliary field in u_x[]
8720 .  a            - The auxiliary field values at this point in space
8721 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8722 .  a_x          - The auxiliary field derivatives at this point in space
8723 .  t            - The current time
8724 .  x            - The coordinates of this point
8725 .  numConstants - The number of constants
8726 .  constants    - The value of each constant
8727 -  f            - The value of the function at this point in space
8728 
8729   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.
8730   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
8731   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8732   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8733 
8734   Level: intermediate
8735 
8736 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8737 @*/
8738 PetscErrorCode DMProjectFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8739                                         void (**funcs)(PetscInt, PetscInt, PetscInt,
8740                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8741                                                        const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8742                                                        PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8743                                         InsertMode mode, Vec localX)
8744 {
8745   PetscErrorCode ierr;
8746 
8747   PetscFunctionBegin;
8748   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8749   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
8750   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
8751   if (!dm->ops->projectfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectFieldLabelLocal",((PetscObject)dm)->type_name);
8752   ierr = (dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
8753   PetscFunctionReturn(0);
8754 }
8755 
8756 /*@C
8757   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.
8758 
8759   Not collective
8760 
8761   Input Parameters:
8762 + dm      - The DM
8763 . time    - The time
8764 . label   - The DMLabel marking the portion of the domain boundary to output
8765 . numIds  - The number of label ids to use
8766 . ids     - The label ids to use for marking
8767 . Nc      - The number of components to set in the output, or PETSC_DETERMINE for all components
8768 . comps   - The components to set in the output, or NULL for all components
8769 . localU  - The input field vector
8770 . funcs   - The functions to evaluate, one per field
8771 - mode    - The insertion mode for values
8772 
8773   Output Parameter:
8774 . localX  - The output vector
8775 
8776    Calling sequence of func:
8777 $    func(PetscInt dim, PetscInt Nf, PetscInt NfAux,
8778 $         const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
8779 $         const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
8780 $         PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[]);
8781 
8782 +  dim          - The spatial dimension
8783 .  Nf           - The number of input fields
8784 .  NfAux        - The number of input auxiliary fields
8785 .  uOff         - The offset of each field in u[]
8786 .  uOff_x       - The offset of each field in u_x[]
8787 .  u            - The field values at this point in space
8788 .  u_t          - The field time derivative at this point in space (or NULL)
8789 .  u_x          - The field derivatives at this point in space
8790 .  aOff         - The offset of each auxiliary field in u[]
8791 .  aOff_x       - The offset of each auxiliary field in u_x[]
8792 .  a            - The auxiliary field values at this point in space
8793 .  a_t          - The auxiliary field time derivative at this point in space (or NULL)
8794 .  a_x          - The auxiliary field derivatives at this point in space
8795 .  t            - The current time
8796 .  x            - The coordinates of this point
8797 .  n            - The face normal
8798 .  numConstants - The number of constants
8799 .  constants    - The value of each constant
8800 -  f            - The value of the function at this point in space
8801 
8802   Note:
8803   There are three different DMs that potentially interact in this function. The output DM, dm, specifies the layout of the values calculates by funcs.
8804   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
8805   a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary DM, attached to the
8806   auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations.
8807 
8808   Level: intermediate
8809 
8810 .seealso: DMProjectField(), DMProjectFieldLabelLocal(), DMProjectFunction(), DMComputeL2Diff()
8811 @*/
8812 PetscErrorCode DMProjectBdFieldLabelLocal(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Nc, const PetscInt comps[], Vec localU,
8813                                           void (**funcs)(PetscInt, PetscInt, PetscInt,
8814                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8815                                                          const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
8816                                                          PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),
8817                                           InsertMode mode, Vec localX)
8818 {
8819   PetscErrorCode ierr;
8820 
8821   PetscFunctionBegin;
8822   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8823   PetscValidHeaderSpecific(localU,VEC_CLASSID,6);
8824   PetscValidHeaderSpecific(localX,VEC_CLASSID,9);
8825   if (!dm->ops->projectbdfieldlabellocal) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMProjectBdFieldLabelLocal",((PetscObject)dm)->type_name);
8826   ierr = (dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX);CHKERRQ(ierr);
8827   PetscFunctionReturn(0);
8828 }
8829 
8830 /*@C
8831   DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
8832 
8833   Input Parameters:
8834 + dm    - The DM
8835 . time  - The time
8836 . funcs - The functions to evaluate for each field component
8837 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8838 - X     - The coefficient vector u_h, a global vector
8839 
8840   Output Parameter:
8841 . diff - The diff ||u - u_h||_2
8842 
8843   Level: developer
8844 
8845 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8846 @*/
8847 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
8848 {
8849   PetscErrorCode ierr;
8850 
8851   PetscFunctionBegin;
8852   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8853   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8854   if (!dm->ops->computel2diff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2Diff",((PetscObject)dm)->type_name);
8855   ierr = (dm->ops->computel2diff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8856   PetscFunctionReturn(0);
8857 }
8858 
8859 /*@C
8860   DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h.
8861 
8862   Collective on dm
8863 
8864   Input Parameters:
8865 + dm    - The DM
8866 , time  - The time
8867 . funcs - The gradient functions to evaluate for each field component
8868 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8869 . X     - The coefficient vector u_h, a global vector
8870 - n     - The vector to project along
8871 
8872   Output Parameter:
8873 . diff - The diff ||(grad u - grad u_h) . n||_2
8874 
8875   Level: developer
8876 
8877 .seealso: DMProjectFunction(), DMComputeL2Diff()
8878 @*/
8879 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)
8880 {
8881   PetscErrorCode ierr;
8882 
8883   PetscFunctionBegin;
8884   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8885   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8886   if (!dm->ops->computel2gradientdiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2GradientDiff",((PetscObject)dm)->type_name);
8887   ierr = (dm->ops->computel2gradientdiff)(dm,time,funcs,ctxs,X,n,diff);CHKERRQ(ierr);
8888   PetscFunctionReturn(0);
8889 }
8890 
8891 /*@C
8892   DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components.
8893 
8894   Collective on dm
8895 
8896   Input Parameters:
8897 + dm    - The DM
8898 . time  - The time
8899 . funcs - The functions to evaluate for each field component
8900 . ctxs  - Optional array of contexts to pass to each function, or NULL.
8901 - X     - The coefficient vector u_h, a global vector
8902 
8903   Output Parameter:
8904 . diff - The array of differences, ||u^f - u^f_h||_2
8905 
8906   Level: developer
8907 
8908 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff()
8909 @*/
8910 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
8911 {
8912   PetscErrorCode ierr;
8913 
8914   PetscFunctionBegin;
8915   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8916   PetscValidHeaderSpecific(X,VEC_CLASSID,5);
8917   if (!dm->ops->computel2fielddiff) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMComputeL2FieldDiff",((PetscObject)dm)->type_name);
8918   ierr = (dm->ops->computel2fielddiff)(dm,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
8919   PetscFunctionReturn(0);
8920 }
8921 
8922 /*@C
8923   DMAdaptLabel - Adapt a dm based on a label with values interpreted as coarsening and refining flags.  Specific implementations of DM maybe have
8924                  specialized flags, but all implementations should accept flag values DM_ADAPT_DETERMINE, DM_ADAPT_KEEP, DM_ADAPT_REFINE, and DM_ADAPT_COARSEN.
8925 
8926   Collective on dm
8927 
8928   Input parameters:
8929 + dm - the pre-adaptation DM object
8930 - label - label with the flags
8931 
8932   Output parameters:
8933 . dmAdapt - the adapted DM object: may be NULL if an adapted DM could not be produced.
8934 
8935   Level: intermediate
8936 
8937 .seealso: DMAdaptMetric(), DMCoarsen(), DMRefine()
8938 @*/
8939 PetscErrorCode DMAdaptLabel(DM dm, DMLabel label, DM *dmAdapt)
8940 {
8941   PetscErrorCode ierr;
8942 
8943   PetscFunctionBegin;
8944   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8945   PetscValidPointer(label,2);
8946   PetscValidPointer(dmAdapt,3);
8947   *dmAdapt = NULL;
8948   if (!dm->ops->adaptlabel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptLabel",((PetscObject)dm)->type_name);
8949   ierr = (dm->ops->adaptlabel)(dm, label, dmAdapt);CHKERRQ(ierr);
8950   if (*dmAdapt) (*dmAdapt)->prealloc_only = dm->prealloc_only;  /* maybe this should go .... */
8951   PetscFunctionReturn(0);
8952 }
8953 
8954 /*@C
8955   DMAdaptMetric - Generates a mesh adapted to the specified metric field using the pragmatic library.
8956 
8957   Input Parameters:
8958 + dm - The DM object
8959 . metric - The metric to which the mesh is adapted, defined vertex-wise.
8960 - 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_".
8961 
8962   Output Parameter:
8963 . dmAdapt  - Pointer to the DM object containing the adapted mesh
8964 
8965   Note: The label in the adapted mesh will be registered under the name of the input DMLabel object
8966 
8967   Level: advanced
8968 
8969 .seealso: DMAdaptLabel(), DMCoarsen(), DMRefine()
8970 @*/
8971 PetscErrorCode DMAdaptMetric(DM dm, Vec metric, DMLabel bdLabel, DM *dmAdapt)
8972 {
8973   PetscErrorCode ierr;
8974 
8975   PetscFunctionBegin;
8976   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8977   PetscValidHeaderSpecific(metric, VEC_CLASSID, 2);
8978   if (bdLabel) PetscValidPointer(bdLabel, 3);
8979   PetscValidPointer(dmAdapt, 4);
8980   *dmAdapt = NULL;
8981   if (!dm->ops->adaptmetric) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMAdaptMetric",((PetscObject)dm)->type_name);
8982   ierr = (dm->ops->adaptmetric)(dm, metric, bdLabel, dmAdapt);CHKERRQ(ierr);
8983   PetscFunctionReturn(0);
8984 }
8985 
8986 /*@C
8987  DMGetNeighbors - Gets an array containing the MPI rank of all the processes neighbors
8988 
8989  Not Collective
8990 
8991  Input Parameter:
8992 .  dm    - The DM
8993 
8994  Output Parameters:
8995 +  nranks - the number of neighbours
8996 -  ranks - the neighbors ranks
8997 
8998  Notes:
8999  Do not free the array, it is freed when the DM is destroyed.
9000 
9001  Level: beginner
9002 
9003  .seealso: DMDAGetNeighbors(), PetscSFGetRootRanks()
9004 @*/
9005 PetscErrorCode DMGetNeighbors(DM dm,PetscInt *nranks,const PetscMPIInt *ranks[])
9006 {
9007   PetscErrorCode ierr;
9008 
9009   PetscFunctionBegin;
9010   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
9011   if (!dm->ops->getneighbors) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM type %s does not implement DMGetNeighbors",((PetscObject)dm)->type_name);
9012   ierr = (dm->ops->getneighbors)(dm,nranks,ranks);CHKERRQ(ierr);
9013   PetscFunctionReturn(0);
9014 }
9015 
9016 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */
9017 
9018 /*
9019     Converts the input vector to a ghosted vector and then calls the standard coloring code.
9020     This has be a different function because it requires DM which is not defined in the Mat library
9021 */
9022 PetscErrorCode  MatFDColoringApply_AIJDM(Mat J,MatFDColoring coloring,Vec x1,void *sctx)
9023 {
9024   PetscErrorCode ierr;
9025 
9026   PetscFunctionBegin;
9027   if (coloring->ctype == IS_COLORING_LOCAL) {
9028     Vec x1local;
9029     DM  dm;
9030     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
9031     if (!dm) SETERRQ(PetscObjectComm((PetscObject)J),PETSC_ERR_ARG_INCOMP,"IS_COLORING_LOCAL requires a DM");
9032     ierr = DMGetLocalVector(dm,&x1local);CHKERRQ(ierr);
9033     ierr = DMGlobalToLocalBegin(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
9034     ierr = DMGlobalToLocalEnd(dm,x1,INSERT_VALUES,x1local);CHKERRQ(ierr);
9035     x1   = x1local;
9036   }
9037   ierr = MatFDColoringApply_AIJ(J,coloring,x1,sctx);CHKERRQ(ierr);
9038   if (coloring->ctype == IS_COLORING_LOCAL) {
9039     DM  dm;
9040     ierr = MatGetDM(J,&dm);CHKERRQ(ierr);
9041     ierr = DMRestoreLocalVector(dm,&x1);CHKERRQ(ierr);
9042   }
9043   PetscFunctionReturn(0);
9044 }
9045 
9046 /*@
9047     MatFDColoringUseDM - allows a MatFDColoring object to use the DM associated with the matrix to use a IS_COLORING_LOCAL coloring
9048 
9049     Input Parameter:
9050 .    coloring - the MatFDColoring object
9051 
9052     Developer Notes:
9053     this routine exists because the PETSc Mat library does not know about the DM objects
9054 
9055     Level: advanced
9056 
9057 .seealso: MatFDColoring, MatFDColoringCreate(), ISColoringType
9058 @*/
9059 PetscErrorCode  MatFDColoringUseDM(Mat coloring,MatFDColoring fdcoloring)
9060 {
9061   PetscFunctionBegin;
9062   coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM;
9063   PetscFunctionReturn(0);
9064 }
9065 
9066 /*@
9067     DMGetCompatibility - determine if two DMs are compatible
9068 
9069     Collective
9070 
9071     Input Parameters:
9072 +    dm1 - the first DM
9073 -    dm2 - the second DM
9074 
9075     Output Parameters:
9076 +    compatible - whether or not the two DMs are compatible
9077 -    set - whether or not the compatible value was set
9078 
9079     Notes:
9080     Two DMs are deemed compatible if they represent the same parallel decomposition
9081     of the same topology. This implies that the section (field data) on one
9082     "makes sense" with respect to the topology and parallel decomposition of the other.
9083     Loosely speaking, compatible DMs represent the same domain and parallel
9084     decomposition, but hold different data.
9085 
9086     Typically, one would confirm compatibility if intending to simultaneously iterate
9087     over a pair of vectors obtained from different DMs.
9088 
9089     For example, two DMDA objects are compatible if they have the same local
9090     and global sizes and the same stencil width. They can have different numbers
9091     of degrees of freedom per node. Thus, one could use the node numbering from
9092     either DM in bounds for a loop over vectors derived from either DM.
9093 
9094     Consider the operation of summing data living on a 2-dof DMDA to data living
9095     on a 1-dof DMDA, which should be compatible, as in the following snippet.
9096 .vb
9097   ...
9098   ierr = DMGetCompatibility(da1,da2,&compatible,&set);CHKERRQ(ierr);
9099   if (set && compatible)  {
9100     ierr = DMDAVecGetArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
9101     ierr = DMDAVecGetArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
9102     ierr = DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL);CHKERRQ(ierr);
9103     for (j=y; j<y+n; ++j) {
9104       for (i=x; i<x+m, ++i) {
9105         arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1];
9106       }
9107     }
9108     ierr = DMDAVecRestoreArrayDOF(da1,vec1,&arr1);CHKERRQ(ierr);
9109     ierr = DMDAVecRestoreArrayDOF(da2,vec2,&arr2);CHKERRQ(ierr);
9110   } else {
9111     SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible");
9112   }
9113   ...
9114 .ve
9115 
9116     Checking compatibility might be expensive for a given implementation of DM,
9117     or might be impossible to unambiguously confirm or deny. For this reason,
9118     this function may decline to determine compatibility, and hence users should
9119     always check the "set" output parameter.
9120 
9121     A DM is always compatible with itself.
9122 
9123     In the current implementation, DMs which live on "unequal" communicators
9124     (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed
9125     incompatible.
9126 
9127     This function is labeled "Collective," as information about all subdomains
9128     is required on each rank. However, in DM implementations which store all this
9129     information locally, this function may be merely "Logically Collective".
9130 
9131     Developer Notes:
9132     Compatibility is assumed to be a symmetric concept; DM A is compatible with DM B
9133     iff B is compatible with A. Thus, this function checks the implementations
9134     of both dm and dmc (if they are of different types), attempting to determine
9135     compatibility. It is left to DM implementers to ensure that symmetry is
9136     preserved. The simplest way to do this is, when implementing type-specific
9137     logic for this function, is to check for existing logic in the implementation
9138     of other DM types and let *set = PETSC_FALSE if found.
9139 
9140     Level: advanced
9141 
9142 .seealso: DM, DMDACreateCompatibleDMDA(), DMStagCreateCompatibleDMStag()
9143 @*/
9144 
9145 PetscErrorCode DMGetCompatibility(DM dm1,DM dm2,PetscBool *compatible,PetscBool *set)
9146 {
9147   PetscErrorCode ierr;
9148   PetscMPIInt    compareResult;
9149   DMType         type,type2;
9150   PetscBool      sameType;
9151 
9152   PetscFunctionBegin;
9153   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
9154   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
9155 
9156   /* Declare a DM compatible with itself */
9157   if (dm1 == dm2) {
9158     *set = PETSC_TRUE;
9159     *compatible = PETSC_TRUE;
9160     PetscFunctionReturn(0);
9161   }
9162 
9163   /* Declare a DM incompatible with a DM that lives on an "unequal"
9164      communicator. Note that this does not preclude compatibility with
9165      DMs living on "congruent" or "similar" communicators, but this must be
9166      determined by the implementation-specific logic */
9167   ierr = MPI_Comm_compare(PetscObjectComm((PetscObject)dm1),PetscObjectComm((PetscObject)dm2),&compareResult);CHKERRQ(ierr);
9168   if (compareResult == MPI_UNEQUAL) {
9169     *set = PETSC_TRUE;
9170     *compatible = PETSC_FALSE;
9171     PetscFunctionReturn(0);
9172   }
9173 
9174   /* Pass to the implementation-specific routine, if one exists. */
9175   if (dm1->ops->getcompatibility) {
9176     ierr = (*dm1->ops->getcompatibility)(dm1,dm2,compatible,set);CHKERRQ(ierr);
9177     if (*set) PetscFunctionReturn(0);
9178   }
9179 
9180   /* If dm1 and dm2 are of different types, then attempt to check compatibility
9181      with an implementation of this function from dm2 */
9182   ierr = DMGetType(dm1,&type);CHKERRQ(ierr);
9183   ierr = DMGetType(dm2,&type2);CHKERRQ(ierr);
9184   ierr = PetscStrcmp(type,type2,&sameType);CHKERRQ(ierr);
9185   if (!sameType && dm2->ops->getcompatibility) {
9186     ierr = (*dm2->ops->getcompatibility)(dm2,dm1,compatible,set);CHKERRQ(ierr); /* Note argument order */
9187   } else {
9188     *set = PETSC_FALSE;
9189   }
9190   PetscFunctionReturn(0);
9191 }
9192 
9193 /*@C
9194   DMMonitorSet - Sets an ADDITIONAL function that is to be used after a solve to monitor discretization performance.
9195 
9196   Logically Collective on DM
9197 
9198   Input Parameters:
9199 + DM - the DM
9200 . f - the monitor function
9201 . mctx - [optional] user-defined context for private data for the monitor routine (use NULL if no context is desired)
9202 - monitordestroy - [optional] routine that frees monitor context (may be NULL)
9203 
9204   Options Database Keys:
9205 - -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to DMMonitorSet(), but
9206                             does not cancel those set via the options database.
9207 
9208   Notes:
9209   Several different monitoring routines may be set by calling
9210   DMMonitorSet() multiple times; all will be called in the
9211   order in which they were set.
9212 
9213   Fortran Notes:
9214   Only a single monitor function can be set for each DM object
9215 
9216   Level: intermediate
9217 
9218 .seealso: DMMonitorCancel()
9219 @*/
9220 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void**))
9221 {
9222   PetscInt       m;
9223   PetscErrorCode ierr;
9224 
9225   PetscFunctionBegin;
9226   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9227   for (m = 0; m < dm->numbermonitors; ++m) {
9228     PetscBool identical;
9229 
9230     ierr = PetscMonitorCompare((PetscErrorCode (*)(void)) f, mctx, monitordestroy, (PetscErrorCode (*)(void)) dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical);CHKERRQ(ierr);
9231     if (identical) PetscFunctionReturn(0);
9232   }
9233   if (dm->numbermonitors >= MAXDMMONITORS) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set");
9234   dm->monitor[dm->numbermonitors]          = f;
9235   dm->monitordestroy[dm->numbermonitors]   = monitordestroy;
9236   dm->monitorcontext[dm->numbermonitors++] = (void *) mctx;
9237   PetscFunctionReturn(0);
9238 }
9239 
9240 /*@
9241   DMMonitorCancel - Clears all the monitor functions for a DM object.
9242 
9243   Logically Collective on DM
9244 
9245   Input Parameter:
9246 . dm - the DM
9247 
9248   Options Database Key:
9249 . -dm_monitor_cancel - cancels all monitors that have been hardwired
9250   into a code by calls to DMonitorSet(), but does not cancel those
9251   set via the options database
9252 
9253   Notes:
9254   There is no way to clear one specific monitor from a DM object.
9255 
9256   Level: intermediate
9257 
9258 .seealso: DMMonitorSet()
9259 @*/
9260 PetscErrorCode DMMonitorCancel(DM dm)
9261 {
9262   PetscErrorCode ierr;
9263   PetscInt       m;
9264 
9265   PetscFunctionBegin;
9266   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9267   for (m = 0; m < dm->numbermonitors; ++m) {
9268     if (dm->monitordestroy[m]) {ierr = (*dm->monitordestroy[m])(&dm->monitorcontext[m]);CHKERRQ(ierr);}
9269   }
9270   dm->numbermonitors = 0;
9271   PetscFunctionReturn(0);
9272 }
9273 
9274 /*@C
9275   DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user
9276 
9277   Collective on DM
9278 
9279   Input Parameters:
9280 + dm   - DM object you wish to monitor
9281 . name - the monitor type one is seeking
9282 . help - message indicating what monitoring is done
9283 . manual - manual page for the monitor
9284 . monitor - the monitor function
9285 - 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
9286 
9287   Output Parameter:
9288 . flg - Flag set if the monitor was created
9289 
9290   Level: developer
9291 
9292 .seealso: PetscOptionsGetViewer(), PetscOptionsGetReal(), PetscOptionsHasName(), PetscOptionsGetString(),
9293           PetscOptionsGetIntArray(), PetscOptionsGetRealArray(), PetscOptionsBool()
9294           PetscOptionsInt(), PetscOptionsString(), PetscOptionsReal(), PetscOptionsBool(),
9295           PetscOptionsName(), PetscOptionsBegin(), PetscOptionsEnd(), PetscOptionsHead(),
9296           PetscOptionsStringArray(),PetscOptionsRealArray(), PetscOptionsScalar(),
9297           PetscOptionsBoolGroupBegin(), PetscOptionsBoolGroup(), PetscOptionsBoolGroupEnd(),
9298           PetscOptionsFList(), PetscOptionsEList()
9299 @*/
9300 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg)
9301 {
9302   PetscViewer       viewer;
9303   PetscViewerFormat format;
9304   PetscErrorCode    ierr;
9305 
9306   PetscFunctionBegin;
9307   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9308   ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) dm), ((PetscObject) dm)->options, ((PetscObject) dm)->prefix, name, &viewer, &format, flg);CHKERRQ(ierr);
9309   if (*flg) {
9310     PetscViewerAndFormat *vf;
9311 
9312     ierr = PetscViewerAndFormatCreate(viewer, format, &vf);CHKERRQ(ierr);
9313     ierr = PetscObjectDereference((PetscObject) viewer);CHKERRQ(ierr);
9314     if (monitorsetup) {ierr = (*monitorsetup)(dm, vf);CHKERRQ(ierr);}
9315     ierr = DMMonitorSet(dm,(PetscErrorCode (*)(DM, void *)) monitor, vf, (PetscErrorCode (*)(void **)) PetscViewerAndFormatDestroy);CHKERRQ(ierr);
9316   }
9317   PetscFunctionReturn(0);
9318 }
9319 
9320 /*@
9321    DMMonitor - runs the user provided monitor routines, if they exist
9322 
9323    Collective on DM
9324 
9325    Input Parameters:
9326 .  dm - The DM
9327 
9328    Level: developer
9329 
9330 .seealso: DMMonitorSet()
9331 @*/
9332 PetscErrorCode DMMonitor(DM dm)
9333 {
9334   PetscInt       m;
9335   PetscErrorCode ierr;
9336 
9337   PetscFunctionBegin;
9338   if (!dm) PetscFunctionReturn(0);
9339   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9340   for (m = 0; m < dm->numbermonitors; ++m) {
9341     ierr = (*dm->monitor[m])(dm, dm->monitorcontext[m]);CHKERRQ(ierr);
9342   }
9343   PetscFunctionReturn(0);
9344 }
9345