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