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