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