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