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