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