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