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