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