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