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