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