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