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