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