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