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