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