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