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