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