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