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