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