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