xref: /petsc/src/dm/interface/dm.c (revision 811e8653d87066e322b7d58d7ef05320c3f6aa91)
1 #include <petsc-private/dmimpl.h>     /*I      "petscdm.h"     I*/
2 #include <petscsf.h>
3 #include <petscds.h>
4 
5 PetscClassId  DM_CLASSID;
6 PetscLogEvent DM_Convert, DM_GlobalToLocal, DM_LocalToGlobal, DM_LocalToLocal;
7 
8 const char *const DMBoundaryTypes[] = {"NONE","GHOSTED","MIRROR","PERIODIC","TWIST","DM_BOUNDARY_",0};
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "DMCreate"
12 /*@
13   DMCreate - Creates an empty DM object. The type can then be set with DMSetType().
14 
15    If you never  call DMSetType()  it will generate an
16    error when you try to use the vector.
17 
18   Collective on MPI_Comm
19 
20   Input Parameter:
21 . comm - The communicator for the DM object
22 
23   Output Parameter:
24 . dm - The DM object
25 
26   Level: beginner
27 
28 .seealso: DMSetType(), DMDA, DMSLICED, DMCOMPOSITE
29 @*/
30 PetscErrorCode  DMCreate(MPI_Comm comm,DM *dm)
31 {
32   DM             v;
33   PetscErrorCode ierr;
34 
35   PetscFunctionBegin;
36   PetscValidPointer(dm,2);
37   *dm = NULL;
38   ierr = PetscSysInitializePackage();CHKERRQ(ierr);
39   ierr = VecInitializePackage();CHKERRQ(ierr);
40   ierr = MatInitializePackage();CHKERRQ(ierr);
41   ierr = DMInitializePackage();CHKERRQ(ierr);
42 
43   ierr = PetscHeaderCreate(v, _p_DM, struct _DMOps, DM_CLASSID, "DM", "Distribution Manager", "DM", comm, DMDestroy, DMView);CHKERRQ(ierr);
44   ierr = PetscMemzero(v->ops, sizeof(struct _DMOps));CHKERRQ(ierr);
45 
46 
47   v->ltogmap              = NULL;
48   v->bs                   = 1;
49   v->coloringtype         = IS_COLORING_GLOBAL;
50   ierr                    = PetscSFCreate(comm, &v->sf);CHKERRQ(ierr);
51   ierr                    = PetscSFCreate(comm, &v->defaultSF);CHKERRQ(ierr);
52   v->defaultSection       = NULL;
53   v->defaultGlobalSection = NULL;
54   v->L                    = NULL;
55   v->maxCell              = NULL;
56   v->dimEmbed             = PETSC_DEFAULT;
57   {
58     PetscInt i;
59     for (i = 0; i < 10; ++i) {
60       v->nullspaceConstructors[i] = NULL;
61     }
62   }
63   ierr = PetscDSCreate(comm, &v->prob);CHKERRQ(ierr);
64   v->dmBC = NULL;
65   v->outputSequenceNum = -1;
66   v->outputSequenceVal = 0.0;
67   ierr = DMSetVecType(v,VECSTANDARD);CHKERRQ(ierr);
68   ierr = DMSetMatType(v,MATAIJ);CHKERRQ(ierr);
69   *dm = v;
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "DMClone"
75 /*@
76   DMClone - Creates a DM object with the same topology as the original.
77 
78   Collective on MPI_Comm
79 
80   Input Parameter:
81 . dm - The original DM object
82 
83   Output Parameter:
84 . newdm  - The new DM object
85 
86   Level: beginner
87 
88 .keywords: DM, topology, create
89 @*/
90 PetscErrorCode DMClone(DM dm, DM *newdm)
91 {
92   PetscSF        sf;
93   Vec            coords;
94   void          *ctx;
95   PetscInt       dim;
96   PetscErrorCode ierr;
97 
98   PetscFunctionBegin;
99   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
100   PetscValidPointer(newdm,2);
101   ierr = DMCreate(PetscObjectComm((PetscObject)dm), newdm);CHKERRQ(ierr);
102   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
103   ierr = DMSetDimension(*newdm, dim);CHKERRQ(ierr);
104   if (dm->ops->clone) {
105     ierr = (*dm->ops->clone)(dm, newdm);CHKERRQ(ierr);
106   }
107   (*newdm)->setupcalled = PETSC_TRUE;
108   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
109   ierr = DMSetPointSF(*newdm, sf);CHKERRQ(ierr);
110   ierr = DMGetApplicationContext(dm, &ctx);CHKERRQ(ierr);
111   ierr = DMSetApplicationContext(*newdm, ctx);CHKERRQ(ierr);
112   ierr = DMGetCoordinatesLocal(dm, &coords);CHKERRQ(ierr);
113   if (coords) {
114     ierr = DMSetCoordinatesLocal(*newdm, coords);CHKERRQ(ierr);
115   } else {
116     ierr = DMGetCoordinates(dm, &coords);CHKERRQ(ierr);
117     if (coords) {ierr = DMSetCoordinates(*newdm, coords);CHKERRQ(ierr);}
118   }
119   if (dm->maxCell) {
120     const PetscReal *maxCell, *L;
121     ierr = DMGetPeriodicity(dm,     &maxCell, &L);CHKERRQ(ierr);
122     ierr = DMSetPeriodicity(*newdm,  maxCell,  L);CHKERRQ(ierr);
123   }
124   PetscFunctionReturn(0);
125 }
126 
127 #undef __FUNCT__
128 #define __FUNCT__ "DMSetVecType"
129 /*@C
130        DMSetVecType - Sets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
131 
132    Logically Collective on DMDA
133 
134    Input Parameter:
135 +  da - initial distributed array
136 .  ctype - the vector type, currently either VECSTANDARD or VECCUSP
137 
138    Options Database:
139 .   -dm_vec_type ctype
140 
141    Level: intermediate
142 
143 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType, VecType, DMGetVecType()
144 @*/
145 PetscErrorCode  DMSetVecType(DM da,VecType ctype)
146 {
147   PetscErrorCode ierr;
148 
149   PetscFunctionBegin;
150   PetscValidHeaderSpecific(da,DM_CLASSID,1);
151   ierr = PetscFree(da->vectype);CHKERRQ(ierr);
152   ierr = PetscStrallocpy(ctype,(char**)&da->vectype);CHKERRQ(ierr);
153   PetscFunctionReturn(0);
154 }
155 
156 #undef __FUNCT__
157 #define __FUNCT__ "DMGetVecType"
158 /*@C
159        DMGetVecType - Gets the type of vector created with DMCreateLocalVector() and DMCreateGlobalVector()
160 
161    Logically Collective on DMDA
162 
163    Input Parameter:
164 .  da - initial distributed array
165 
166    Output Parameter:
167 .  ctype - the vector type
168 
169    Level: intermediate
170 
171 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType, VecType
172 @*/
173 PetscErrorCode  DMGetVecType(DM da,VecType *ctype)
174 {
175   PetscFunctionBegin;
176   PetscValidHeaderSpecific(da,DM_CLASSID,1);
177   *ctype = da->vectype;
178   PetscFunctionReturn(0);
179 }
180 
181 #undef __FUNCT__
182 #define __FUNCT__ "VecGetDM"
183 /*@
184   VecGetDM - Gets the DM defining the data layout of the vector
185 
186   Not collective
187 
188   Input Parameter:
189 . v - The Vec
190 
191   Output Parameter:
192 . dm - The DM
193 
194   Level: intermediate
195 
196 .seealso: VecSetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
197 @*/
198 PetscErrorCode VecGetDM(Vec v, DM *dm)
199 {
200   PetscErrorCode ierr;
201 
202   PetscFunctionBegin;
203   PetscValidHeaderSpecific(v,VEC_CLASSID,1);
204   PetscValidPointer(dm,2);
205   ierr = PetscObjectQuery((PetscObject) v, "__PETSc_dm", (PetscObject*) dm);CHKERRQ(ierr);
206   PetscFunctionReturn(0);
207 }
208 
209 #undef __FUNCT__
210 #define __FUNCT__ "VecSetDM"
211 /*@
212   VecSetDM - Sets the DM defining the data layout of the vector
213 
214   Not collective
215 
216   Input Parameters:
217 + v - The Vec
218 - dm - The DM
219 
220   Level: intermediate
221 
222 .seealso: VecGetDM(), DMGetLocalVector(), DMGetGlobalVector(), DMSetVecType()
223 @*/
224 PetscErrorCode VecSetDM(Vec v, DM dm)
225 {
226   PetscErrorCode ierr;
227 
228   PetscFunctionBegin;
229   PetscValidHeaderSpecific(v,VEC_CLASSID,1);
230   if (dm) PetscValidHeaderSpecific(dm,DM_CLASSID,2);
231   ierr = PetscObjectCompose((PetscObject) v, "__PETSc_dm", (PetscObject) dm);CHKERRQ(ierr);
232   PetscFunctionReturn(0);
233 }
234 
235 #undef __FUNCT__
236 #define __FUNCT__ "DMSetMatType"
237 /*@C
238        DMSetMatType - Sets the type of matrix created with DMCreateMatrix()
239 
240    Logically Collective on DM
241 
242    Input Parameter:
243 +  dm - the DM context
244 .  ctype - the matrix type
245 
246    Options Database:
247 .   -dm_mat_type ctype
248 
249    Level: intermediate
250 
251 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMGetMatType()
252 @*/
253 PetscErrorCode  DMSetMatType(DM dm,MatType ctype)
254 {
255   PetscErrorCode ierr;
256 
257   PetscFunctionBegin;
258   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
259   ierr = PetscFree(dm->mattype);CHKERRQ(ierr);
260   ierr = PetscStrallocpy(ctype,(char**)&dm->mattype);CHKERRQ(ierr);
261   PetscFunctionReturn(0);
262 }
263 
264 #undef __FUNCT__
265 #define __FUNCT__ "DMGetMatType"
266 /*@C
267        DMGetMatType - Gets the type of matrix created with DMCreateMatrix()
268 
269    Logically Collective on DM
270 
271    Input Parameter:
272 .  dm - the DM context
273 
274    Output Parameter:
275 .  ctype - the matrix type
276 
277    Options Database:
278 .   -dm_mat_type ctype
279 
280    Level: intermediate
281 
282 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMCreateMatrix(), DMSetMatrixPreallocateOnly(), MatType, DMSetMatType()
283 @*/
284 PetscErrorCode  DMGetMatType(DM dm,MatType *ctype)
285 {
286   PetscFunctionBegin;
287   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
288   *ctype = dm->mattype;
289   PetscFunctionReturn(0);
290 }
291 
292 #undef __FUNCT__
293 #define __FUNCT__ "MatGetDM"
294 /*@
295   MatGetDM - Gets the DM defining the data layout of the matrix
296 
297   Not collective
298 
299   Input Parameter:
300 . A - The Mat
301 
302   Output Parameter:
303 . dm - The DM
304 
305   Level: intermediate
306 
307 .seealso: MatSetDM(), DMCreateMatrix(), DMSetMatType()
308 @*/
309 PetscErrorCode MatGetDM(Mat A, DM *dm)
310 {
311   PetscErrorCode ierr;
312 
313   PetscFunctionBegin;
314   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
315   PetscValidPointer(dm,2);
316   ierr = PetscObjectQuery((PetscObject) A, "__PETSc_dm", (PetscObject*) dm);CHKERRQ(ierr);
317   PetscFunctionReturn(0);
318 }
319 
320 #undef __FUNCT__
321 #define __FUNCT__ "MatSetDM"
322 /*@
323   MatSetDM - Sets the DM defining the data layout of the matrix
324 
325   Not collective
326 
327   Input Parameters:
328 + A - The Mat
329 - dm - The DM
330 
331   Level: intermediate
332 
333 .seealso: MatGetDM(), DMCreateMatrix(), DMSetMatType()
334 @*/
335 PetscErrorCode MatSetDM(Mat A, DM dm)
336 {
337   PetscErrorCode ierr;
338 
339   PetscFunctionBegin;
340   PetscValidHeaderSpecific(A,MAT_CLASSID,1);
341   if (dm) PetscValidHeaderSpecific(dm,DM_CLASSID,2);
342   ierr = PetscObjectCompose((PetscObject) A, "__PETSc_dm", (PetscObject) dm);CHKERRQ(ierr);
343   PetscFunctionReturn(0);
344 }
345 
346 #undef __FUNCT__
347 #define __FUNCT__ "DMSetOptionsPrefix"
348 /*@C
349    DMSetOptionsPrefix - Sets the prefix used for searching for all
350    DMDA options in the database.
351 
352    Logically Collective on DMDA
353 
354    Input Parameter:
355 +  da - the DMDA context
356 -  prefix - the prefix to prepend to all option names
357 
358    Notes:
359    A hyphen (-) must NOT be given at the beginning of the prefix name.
360    The first character of all runtime options is AUTOMATICALLY the hyphen.
361 
362    Level: advanced
363 
364 .keywords: DMDA, set, options, prefix, database
365 
366 .seealso: DMSetFromOptions()
367 @*/
368 PetscErrorCode  DMSetOptionsPrefix(DM dm,const char prefix[])
369 {
370   PetscErrorCode ierr;
371 
372   PetscFunctionBegin;
373   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
374   ierr = PetscObjectSetOptionsPrefix((PetscObject)dm,prefix);CHKERRQ(ierr);
375   PetscFunctionReturn(0);
376 }
377 
378 #undef __FUNCT__
379 #define __FUNCT__ "DMDestroy"
380 /*@
381     DMDestroy - Destroys a vector packer or DMDA.
382 
383     Collective on DM
384 
385     Input Parameter:
386 .   dm - the DM object to destroy
387 
388     Level: developer
389 
390 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
391 
392 @*/
393 PetscErrorCode  DMDestroy(DM *dm)
394 {
395   PetscInt       i, cnt = 0;
396   DMNamedVecLink nlink,nnext;
397   PetscErrorCode ierr;
398 
399   PetscFunctionBegin;
400   if (!*dm) PetscFunctionReturn(0);
401   PetscValidHeaderSpecific((*dm),DM_CLASSID,1);
402 
403   /* count all the circular references of DM and its contained Vecs */
404   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
405     if ((*dm)->localin[i])  cnt++;
406     if ((*dm)->globalin[i]) cnt++;
407   }
408   for (nlink=(*dm)->namedglobal; nlink; nlink=nlink->next) cnt++;
409   for (nlink=(*dm)->namedlocal; nlink; nlink=nlink->next) cnt++;
410   if ((*dm)->x) {
411     DM obj;
412     ierr = VecGetDM((*dm)->x, &obj);CHKERRQ(ierr);
413     if (obj == *dm) cnt++;
414   }
415 
416   if (--((PetscObject)(*dm))->refct - cnt > 0) {*dm = 0; PetscFunctionReturn(0);}
417   /*
418      Need this test because the dm references the vectors that
419      reference the dm, so destroying the dm calls destroy on the
420      vectors that cause another destroy on the dm
421   */
422   if (((PetscObject)(*dm))->refct < 0) PetscFunctionReturn(0);
423   ((PetscObject) (*dm))->refct = 0;
424   for (i=0; i<DM_MAX_WORK_VECTORS; i++) {
425     if ((*dm)->localout[i]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Destroying a DM that has a local vector obtained with DMGetLocalVector()");
426     ierr = VecDestroy(&(*dm)->localin[i]);CHKERRQ(ierr);
427   }
428   nnext=(*dm)->namedglobal;
429   (*dm)->namedglobal = NULL;
430   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named vectors */
431     nnext = nlink->next;
432     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
433     ierr = PetscFree(nlink->name);CHKERRQ(ierr);
434     ierr = VecDestroy(&nlink->X);CHKERRQ(ierr);
435     ierr = PetscFree(nlink);CHKERRQ(ierr);
436   }
437   nnext=(*dm)->namedlocal;
438   (*dm)->namedlocal = NULL;
439   for (nlink=nnext; nlink; nlink=nnext) { /* Destroy the named local vectors */
440     nnext = nlink->next;
441     if (nlink->status != DMVEC_STATUS_IN) SETERRQ1(((PetscObject)*dm)->comm,PETSC_ERR_ARG_WRONGSTATE,"DM still has Vec named '%s' checked out",nlink->name);
442     ierr = PetscFree(nlink->name);CHKERRQ(ierr);
443     ierr = VecDestroy(&nlink->X);CHKERRQ(ierr);
444     ierr = PetscFree(nlink);CHKERRQ(ierr);
445   }
446 
447   /* Destroy the list of hooks */
448   {
449     DMCoarsenHookLink link,next;
450     for (link=(*dm)->coarsenhook; link; link=next) {
451       next = link->next;
452       ierr = PetscFree(link);CHKERRQ(ierr);
453     }
454     (*dm)->coarsenhook = NULL;
455   }
456   {
457     DMRefineHookLink link,next;
458     for (link=(*dm)->refinehook; link; link=next) {
459       next = link->next;
460       ierr = PetscFree(link);CHKERRQ(ierr);
461     }
462     (*dm)->refinehook = NULL;
463   }
464   {
465     DMSubDomainHookLink link,next;
466     for (link=(*dm)->subdomainhook; link; link=next) {
467       next = link->next;
468       ierr = PetscFree(link);CHKERRQ(ierr);
469     }
470     (*dm)->subdomainhook = NULL;
471   }
472   {
473     DMGlobalToLocalHookLink link,next;
474     for (link=(*dm)->gtolhook; link; link=next) {
475       next = link->next;
476       ierr = PetscFree(link);CHKERRQ(ierr);
477     }
478     (*dm)->gtolhook = NULL;
479   }
480   {
481     DMLocalToGlobalHookLink link,next;
482     for (link=(*dm)->ltoghook; link; link=next) {
483       next = link->next;
484       ierr = PetscFree(link);CHKERRQ(ierr);
485     }
486     (*dm)->ltoghook = NULL;
487   }
488   /* Destroy the work arrays */
489   {
490     DMWorkLink link,next;
491     if ((*dm)->workout) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Work array still checked out");
492     for (link=(*dm)->workin; link; link=next) {
493       next = link->next;
494       ierr = PetscFree(link->mem);CHKERRQ(ierr);
495       ierr = PetscFree(link);CHKERRQ(ierr);
496     }
497     (*dm)->workin = NULL;
498   }
499 
500   ierr = PetscObjectDestroy(&(*dm)->dmksp);CHKERRQ(ierr);
501   ierr = PetscObjectDestroy(&(*dm)->dmsnes);CHKERRQ(ierr);
502   ierr = PetscObjectDestroy(&(*dm)->dmts);CHKERRQ(ierr);
503 
504   if ((*dm)->ctx && (*dm)->ctxdestroy) {
505     ierr = (*(*dm)->ctxdestroy)(&(*dm)->ctx);CHKERRQ(ierr);
506   }
507   ierr = VecDestroy(&(*dm)->x);CHKERRQ(ierr);
508   ierr = MatFDColoringDestroy(&(*dm)->fd);CHKERRQ(ierr);
509   ierr = DMClearGlobalVectors(*dm);CHKERRQ(ierr);
510   ierr = ISLocalToGlobalMappingDestroy(&(*dm)->ltogmap);CHKERRQ(ierr);
511   ierr = PetscFree((*dm)->vectype);CHKERRQ(ierr);
512   ierr = PetscFree((*dm)->mattype);CHKERRQ(ierr);
513 
514   ierr = PetscSectionDestroy(&(*dm)->defaultSection);CHKERRQ(ierr);
515   ierr = PetscSectionDestroy(&(*dm)->defaultGlobalSection);CHKERRQ(ierr);
516   ierr = PetscLayoutDestroy(&(*dm)->map);CHKERRQ(ierr);
517   ierr = PetscSFDestroy(&(*dm)->sf);CHKERRQ(ierr);
518   ierr = PetscSFDestroy(&(*dm)->defaultSF);CHKERRQ(ierr);
519 
520   ierr = DMDestroy(&(*dm)->coordinateDM);CHKERRQ(ierr);
521   ierr = VecDestroy(&(*dm)->coordinates);CHKERRQ(ierr);
522   ierr = VecDestroy(&(*dm)->coordinatesLocal);CHKERRQ(ierr);
523   ierr = PetscFree((*dm)->maxCell);CHKERRQ(ierr);
524   ierr = PetscFree((*dm)->L);CHKERRQ(ierr);
525 
526   ierr = PetscDSDestroy(&(*dm)->prob);CHKERRQ(ierr);
527   ierr = DMDestroy(&(*dm)->dmBC);CHKERRQ(ierr);
528   /* if memory was published with SAWs then destroy it */
529   ierr = PetscObjectSAWsViewOff((PetscObject)*dm);CHKERRQ(ierr);
530 
531   ierr = (*(*dm)->ops->destroy)(*dm);CHKERRQ(ierr);
532   /* We do not destroy (*dm)->data here so that we can reference count backend objects */
533   ierr = PetscHeaderDestroy(dm);CHKERRQ(ierr);
534   PetscFunctionReturn(0);
535 }
536 
537 #undef __FUNCT__
538 #define __FUNCT__ "DMSetUp"
539 /*@
540     DMSetUp - sets up the data structures inside a DM object
541 
542     Collective on DM
543 
544     Input Parameter:
545 .   dm - the DM object to setup
546 
547     Level: developer
548 
549 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
550 
551 @*/
552 PetscErrorCode  DMSetUp(DM dm)
553 {
554   PetscErrorCode ierr;
555 
556   PetscFunctionBegin;
557   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
558   if (dm->setupcalled) PetscFunctionReturn(0);
559   if (dm->ops->setup) {
560     ierr = (*dm->ops->setup)(dm);CHKERRQ(ierr);
561   }
562   dm->setupcalled = PETSC_TRUE;
563   PetscFunctionReturn(0);
564 }
565 
566 #undef __FUNCT__
567 #define __FUNCT__ "DMSetFromOptions"
568 /*@
569     DMSetFromOptions - sets parameters in a DM from the options database
570 
571     Collective on DM
572 
573     Input Parameter:
574 .   dm - the DM object to set options for
575 
576     Options Database:
577 +   -dm_preallocate_only: Only preallocate the matrix for DMCreateMatrix(), but do not fill it with zeros
578 .   -dm_vec_type <type>  type of vector to create inside DM
579 .   -dm_mat_type <type>  type of matrix to create inside DM
580 -   -dm_coloring_type <global or ghosted>
581 
582     Level: developer
583 
584 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
585 
586 @*/
587 PetscErrorCode  DMSetFromOptions(DM dm)
588 {
589   char           typeName[256];
590   PetscBool      flg;
591   PetscErrorCode ierr;
592 
593   PetscFunctionBegin;
594   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
595   ierr = PetscObjectOptionsBegin((PetscObject)dm);CHKERRQ(ierr);
596   ierr = PetscOptionsBool("-dm_preallocate_only","only preallocate matrix, but do not set column indices","DMSetMatrixPreallocateOnly",dm->prealloc_only,&dm->prealloc_only,NULL);CHKERRQ(ierr);
597   ierr = PetscOptionsFList("-dm_vec_type","Vector type used for created vectors","DMSetVecType",VecList,dm->vectype,typeName,256,&flg);CHKERRQ(ierr);
598   if (flg) {
599     ierr = DMSetVecType(dm,typeName);CHKERRQ(ierr);
600   }
601   ierr = PetscOptionsFList("-dm_mat_type","Matrix type used for created matrices","DMSetMatType",MatList,dm->mattype ? dm->mattype : typeName,typeName,sizeof(typeName),&flg);CHKERRQ(ierr);
602   if (flg) {
603     ierr = DMSetMatType(dm,typeName);CHKERRQ(ierr);
604   }
605   ierr = PetscOptionsEnum("-dm_is_coloring_type","Global or local coloring of Jacobian","ISColoringType",ISColoringTypes,(PetscEnum)dm->coloringtype,(PetscEnum*)&dm->coloringtype,NULL);CHKERRQ(ierr);
606   if (dm->ops->setfromoptions) {
607     ierr = (*dm->ops->setfromoptions)(dm);CHKERRQ(ierr);
608   }
609   /* process any options handlers added with PetscObjectAddOptionsHandler() */
610   ierr = PetscObjectProcessOptionsHandlers((PetscObject) dm);CHKERRQ(ierr);
611   ierr = PetscOptionsEnd();CHKERRQ(ierr);
612   PetscFunctionReturn(0);
613 }
614 
615 #undef __FUNCT__
616 #define __FUNCT__ "DMView"
617 /*@C
618     DMView - Views a vector packer or DMDA.
619 
620     Collective on DM
621 
622     Input Parameter:
623 +   dm - the DM object to view
624 -   v - the viewer
625 
626     Level: developer
627 
628 .seealso DMDestroy(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
629 
630 @*/
631 PetscErrorCode  DMView(DM dm,PetscViewer v)
632 {
633   PetscErrorCode ierr;
634   PetscBool      isbinary;
635 
636   PetscFunctionBegin;
637   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
638   if (!v) {
639     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)dm),&v);CHKERRQ(ierr);
640   }
641   ierr = PetscObjectPrintClassNamePrefixType((PetscObject)dm,v);CHKERRQ(ierr);
642   ierr = PetscObjectTypeCompare((PetscObject)v,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
643   if (isbinary) {
644     PetscInt classid = DM_FILE_CLASSID;
645     char     type[256];
646 
647     ierr = PetscViewerBinaryWrite(v,&classid,1,PETSC_INT,PETSC_FALSE);CHKERRQ(ierr);
648     ierr = PetscStrncpy(type,((PetscObject)dm)->type_name,256);CHKERRQ(ierr);
649     ierr = PetscViewerBinaryWrite(v,type,256,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
650   }
651   if (dm->ops->view) {
652     ierr = (*dm->ops->view)(dm,v);CHKERRQ(ierr);
653   }
654   PetscFunctionReturn(0);
655 }
656 
657 #undef __FUNCT__
658 #define __FUNCT__ "DMCreateGlobalVector"
659 /*@
660     DMCreateGlobalVector - Creates a global vector from a DMDA or DMComposite object
661 
662     Collective on DM
663 
664     Input Parameter:
665 .   dm - the DM object
666 
667     Output Parameter:
668 .   vec - the global vector
669 
670     Level: beginner
671 
672 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
673 
674 @*/
675 PetscErrorCode  DMCreateGlobalVector(DM dm,Vec *vec)
676 {
677   PetscErrorCode ierr;
678 
679   PetscFunctionBegin;
680   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
681   ierr = (*dm->ops->createglobalvector)(dm,vec);CHKERRQ(ierr);
682   PetscFunctionReturn(0);
683 }
684 
685 #undef __FUNCT__
686 #define __FUNCT__ "DMCreateLocalVector"
687 /*@
688     DMCreateLocalVector - Creates a local vector from a DMDA or DMComposite object
689 
690     Not Collective
691 
692     Input Parameter:
693 .   dm - the DM object
694 
695     Output Parameter:
696 .   vec - the local vector
697 
698     Level: beginner
699 
700 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
701 
702 @*/
703 PetscErrorCode  DMCreateLocalVector(DM dm,Vec *vec)
704 {
705   PetscErrorCode ierr;
706 
707   PetscFunctionBegin;
708   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
709   ierr = (*dm->ops->createlocalvector)(dm,vec);CHKERRQ(ierr);
710   PetscFunctionReturn(0);
711 }
712 
713 #undef __FUNCT__
714 #define __FUNCT__ "DMGetLocalToGlobalMapping"
715 /*@
716    DMGetLocalToGlobalMapping - Accesses the local-to-global mapping in a DM.
717 
718    Collective on DM
719 
720    Input Parameter:
721 .  dm - the DM that provides the mapping
722 
723    Output Parameter:
724 .  ltog - the mapping
725 
726    Level: intermediate
727 
728    Notes:
729    This mapping can then be used by VecSetLocalToGlobalMapping() or
730    MatSetLocalToGlobalMapping().
731 
732 .seealso: DMCreateLocalVector()
733 @*/
734 PetscErrorCode  DMGetLocalToGlobalMapping(DM dm,ISLocalToGlobalMapping *ltog)
735 {
736   PetscErrorCode ierr;
737 
738   PetscFunctionBegin;
739   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
740   PetscValidPointer(ltog,2);
741   if (!dm->ltogmap) {
742     PetscSection section, sectionGlobal;
743 
744     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
745     if (section) {
746       PetscInt *ltog;
747       PetscInt pStart, pEnd, size, p, l;
748 
749       ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
750       ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
751       ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
752       ierr = PetscMalloc1(size, &ltog);CHKERRQ(ierr); /* We want the local+overlap size */
753       for (p = pStart, l = 0; p < pEnd; ++p) {
754         PetscInt dof, off, c;
755 
756         /* Should probably use constrained dofs */
757         ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
758         ierr = PetscSectionGetOffset(sectionGlobal, p, &off);CHKERRQ(ierr);
759         for (c = 0; c < dof; ++c, ++l) {
760           ltog[l] = off+c;
761         }
762       }
763       ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_SELF, 1,size, ltog, PETSC_OWN_POINTER, &dm->ltogmap);CHKERRQ(ierr);
764       ierr = PetscLogObjectParent((PetscObject)dm, (PetscObject)dm->ltogmap);CHKERRQ(ierr);
765     } else {
766       if (!dm->ops->getlocaltoglobalmapping) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"DM can not create LocalToGlobalMapping");
767       ierr = (*dm->ops->getlocaltoglobalmapping)(dm);CHKERRQ(ierr);
768     }
769   }
770   *ltog = dm->ltogmap;
771   PetscFunctionReturn(0);
772 }
773 
774 #undef __FUNCT__
775 #define __FUNCT__ "DMGetBlockSize"
776 /*@
777    DMGetBlockSize - Gets the inherent block size associated with a DM
778 
779    Not Collective
780 
781    Input Parameter:
782 .  dm - the DM with block structure
783 
784    Output Parameter:
785 .  bs - the block size, 1 implies no exploitable block structure
786 
787    Level: intermediate
788 
789 .seealso: ISCreateBlock(), VecSetBlockSize(), MatSetBlockSize(), DMGetLocalToGlobalMapping()
790 @*/
791 PetscErrorCode  DMGetBlockSize(DM dm,PetscInt *bs)
792 {
793   PetscFunctionBegin;
794   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
795   PetscValidPointer(bs,2);
796   if (dm->bs < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"DM does not have enough information to provide a block size yet");
797   *bs = dm->bs;
798   PetscFunctionReturn(0);
799 }
800 
801 #undef __FUNCT__
802 #define __FUNCT__ "DMCreateInterpolation"
803 /*@
804     DMCreateInterpolation - Gets interpolation matrix between two DMDA or DMComposite objects
805 
806     Collective on DM
807 
808     Input Parameter:
809 +   dm1 - the DM object
810 -   dm2 - the second, finer DM object
811 
812     Output Parameter:
813 +  mat - the interpolation
814 -  vec - the scaling (optional)
815 
816     Level: developer
817 
818     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
819         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the interpolation.
820 
821         For DMDA objects you can use this interpolation (more precisely the interpolation from the DMGetCoordinateDM()) to interpolate the mesh coordinate vectors
822         EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic.
823 
824 
825 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMRefine(), DMCoarsen()
826 
827 @*/
828 PetscErrorCode  DMCreateInterpolation(DM dm1,DM dm2,Mat *mat,Vec *vec)
829 {
830   PetscErrorCode ierr;
831 
832   PetscFunctionBegin;
833   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
834   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
835   ierr = (*dm1->ops->createinterpolation)(dm1,dm2,mat,vec);CHKERRQ(ierr);
836   PetscFunctionReturn(0);
837 }
838 
839 #undef __FUNCT__
840 #define __FUNCT__ "DMCreateInjection"
841 /*@
842     DMCreateInjection - Gets injection matrix between two DMDA or DMComposite objects
843 
844     Collective on DM
845 
846     Input Parameter:
847 +   dm1 - the DM object
848 -   dm2 - the second, finer DM object
849 
850     Output Parameter:
851 .   ctx - the injection
852 
853     Level: developer
854 
855    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
856         DMCoarsen(). The coordinates set into the DMDA are completely ignored in computing the injection.
857 
858 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateColoring(), DMCreateMatrix(), DMCreateInterpolation()
859 
860 @*/
861 PetscErrorCode  DMCreateInjection(DM dm1,DM dm2,VecScatter *ctx)
862 {
863   PetscErrorCode ierr;
864 
865   PetscFunctionBegin;
866   PetscValidHeaderSpecific(dm1,DM_CLASSID,1);
867   PetscValidHeaderSpecific(dm2,DM_CLASSID,2);
868   ierr = (*dm1->ops->getinjection)(dm1,dm2,ctx);CHKERRQ(ierr);
869   PetscFunctionReturn(0);
870 }
871 
872 #undef __FUNCT__
873 #define __FUNCT__ "DMCreateColoring"
874 /*@
875     DMCreateColoring - Gets coloring for a DM
876 
877     Collective on DM
878 
879     Input Parameter:
880 +   dm - the DM object
881 -   ctype - IS_COLORING_GHOSTED or IS_COLORING_GLOBAL
882 
883     Output Parameter:
884 .   coloring - the coloring
885 
886     Level: developer
887 
888 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateMatrix(), DMSetMatType()
889 
890 @*/
891 PetscErrorCode  DMCreateColoring(DM dm,ISColoringType ctype,ISColoring *coloring)
892 {
893   PetscErrorCode ierr;
894 
895   PetscFunctionBegin;
896   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
897   if (!dm->ops->getcoloring) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No coloring for this type of DM yet");
898   ierr = (*dm->ops->getcoloring)(dm,ctype,coloring);CHKERRQ(ierr);
899   PetscFunctionReturn(0);
900 }
901 
902 #undef __FUNCT__
903 #define __FUNCT__ "DMCreateMatrix"
904 /*@
905     DMCreateMatrix - Gets empty Jacobian for a DMDA or DMComposite
906 
907     Collective on DM
908 
909     Input Parameter:
910 .   dm - the DM object
911 
912     Output Parameter:
913 .   mat - the empty Jacobian
914 
915     Level: beginner
916 
917     Notes: This properly preallocates the number of nonzeros in the sparse matrix so you
918        do not need to do it yourself.
919 
920        By default it also sets the nonzero structure and puts in the zero entries. To prevent setting
921        the nonzero pattern call DMDASetMatPreallocateOnly()
922 
923        For structured grid problems, when you call MatView() on this matrix it is displayed using the global natural ordering, NOT in the ordering used
924        internally by PETSc.
925 
926        For structured grid problems, in general it is easiest to use MatSetValuesStencil() or MatSetValuesLocal() to put values into the matrix because MatSetValues() requires
927        the indices for the global numbering for DMDAs which is complicated.
928 
929 .seealso DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMSetMatType()
930 
931 @*/
932 PetscErrorCode  DMCreateMatrix(DM dm,Mat *mat)
933 {
934   PetscErrorCode ierr;
935 
936   PetscFunctionBegin;
937   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
938   ierr = MatInitializePackage();CHKERRQ(ierr);
939   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
940   PetscValidPointer(mat,3);
941   ierr = (*dm->ops->creatematrix)(dm,mat);CHKERRQ(ierr);
942   PetscFunctionReturn(0);
943 }
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMSetMatrixPreallocateOnly"
947 /*@
948   DMSetMatrixPreallocateOnly - When DMCreateMatrix() is called the matrix will be properly
949     preallocated but the nonzero structure and zero values will not be set.
950 
951   Logically Collective on DMDA
952 
953   Input Parameter:
954 + dm - the DM
955 - only - PETSC_TRUE if only want preallocation
956 
957   Level: developer
958 .seealso DMCreateMatrix()
959 @*/
960 PetscErrorCode DMSetMatrixPreallocateOnly(DM dm, PetscBool only)
961 {
962   PetscFunctionBegin;
963   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
964   dm->prealloc_only = only;
965   PetscFunctionReturn(0);
966 }
967 
968 #undef __FUNCT__
969 #define __FUNCT__ "DMGetWorkArray"
970 /*@C
971   DMGetWorkArray - Gets a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
972 
973   Not Collective
974 
975   Input Parameters:
976 + dm - the DM object
977 . count - The minium size
978 - dtype - data type (PETSC_REAL, PETSC_SCALAR, PETSC_INT)
979 
980   Output Parameter:
981 . array - the work array
982 
983   Level: developer
984 
985 .seealso DMDestroy(), DMCreate()
986 @*/
987 PetscErrorCode DMGetWorkArray(DM dm,PetscInt count,PetscDataType dtype,void *mem)
988 {
989   PetscErrorCode ierr;
990   DMWorkLink     link;
991   size_t         size;
992 
993   PetscFunctionBegin;
994   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
995   PetscValidPointer(mem,4);
996   if (dm->workin) {
997     link       = dm->workin;
998     dm->workin = dm->workin->next;
999   } else {
1000     ierr = PetscNewLog(dm,&link);CHKERRQ(ierr);
1001   }
1002   ierr = PetscDataTypeGetSize(dtype,&size);CHKERRQ(ierr);
1003   if (size*count > link->bytes) {
1004     ierr        = PetscFree(link->mem);CHKERRQ(ierr);
1005     ierr        = PetscMalloc(size*count,&link->mem);CHKERRQ(ierr);
1006     link->bytes = size*count;
1007   }
1008   link->next   = dm->workout;
1009   dm->workout  = link;
1010   *(void**)mem = link->mem;
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "DMRestoreWorkArray"
1016 /*@C
1017   DMRestoreWorkArray - Restores a work array guaranteed to be at least the input size, restore with DMRestoreWorkArray()
1018 
1019   Not Collective
1020 
1021   Input Parameters:
1022 + dm - the DM object
1023 . count - The minium size
1024 - dtype - data type (PETSC_REAL, PETSC_SCALAR, PETSC_INT)
1025 
1026   Output Parameter:
1027 . array - the work array
1028 
1029   Level: developer
1030 
1031 .seealso DMDestroy(), DMCreate()
1032 @*/
1033 PetscErrorCode DMRestoreWorkArray(DM dm,PetscInt count,PetscDataType dtype,void *mem)
1034 {
1035   DMWorkLink *p,link;
1036 
1037   PetscFunctionBegin;
1038   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1039   PetscValidPointer(mem,4);
1040   for (p=&dm->workout; (link=*p); p=&link->next) {
1041     if (link->mem == *(void**)mem) {
1042       *p           = link->next;
1043       link->next   = dm->workin;
1044       dm->workin   = link;
1045       *(void**)mem = NULL;
1046       PetscFunctionReturn(0);
1047     }
1048   }
1049   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Array was not checked out");
1050   PetscFunctionReturn(0);
1051 }
1052 
1053 #undef __FUNCT__
1054 #define __FUNCT__ "DMSetNullSpaceConstructor"
1055 PetscErrorCode DMSetNullSpaceConstructor(DM dm, PetscInt field, PetscErrorCode (*nullsp)(DM dm, PetscInt field, MatNullSpace *nullSpace))
1056 {
1057   PetscFunctionBegin;
1058   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1059   if (field >= 10) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot handle %d >= 10 fields", field);
1060   dm->nullspaceConstructors[field] = nullsp;
1061   PetscFunctionReturn(0);
1062 }
1063 
1064 #undef __FUNCT__
1065 #define __FUNCT__ "DMCreateFieldIS"
1066 /*@C
1067   DMCreateFieldIS - Creates a set of IS objects with the global indices of dofs for each field
1068 
1069   Not collective
1070 
1071   Input Parameter:
1072 . dm - the DM object
1073 
1074   Output Parameters:
1075 + numFields  - The number of fields (or NULL if not requested)
1076 . fieldNames - The name for each field (or NULL if not requested)
1077 - fields     - The global indices for each field (or NULL if not requested)
1078 
1079   Level: intermediate
1080 
1081   Notes:
1082   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1083   PetscFree(), every entry of fields should be destroyed with ISDestroy(), and both arrays should be freed with
1084   PetscFree().
1085 
1086 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix()
1087 @*/
1088 PetscErrorCode DMCreateFieldIS(DM dm, PetscInt *numFields, char ***fieldNames, IS **fields)
1089 {
1090   PetscSection   section, sectionGlobal;
1091   PetscErrorCode ierr;
1092 
1093   PetscFunctionBegin;
1094   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1095   if (numFields) {
1096     PetscValidPointer(numFields,2);
1097     *numFields = 0;
1098   }
1099   if (fieldNames) {
1100     PetscValidPointer(fieldNames,3);
1101     *fieldNames = NULL;
1102   }
1103   if (fields) {
1104     PetscValidPointer(fields,4);
1105     *fields = NULL;
1106   }
1107   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1108   if (section) {
1109     PetscInt *fieldSizes, **fieldIndices;
1110     PetscInt nF, f, pStart, pEnd, p;
1111 
1112     ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1113     ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1114     ierr = PetscMalloc2(nF,&fieldSizes,nF,&fieldIndices);CHKERRQ(ierr);
1115     ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1116     for (f = 0; f < nF; ++f) {
1117       fieldSizes[f] = 0;
1118     }
1119     for (p = pStart; p < pEnd; ++p) {
1120       PetscInt gdof;
1121 
1122       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1123       if (gdof > 0) {
1124         for (f = 0; f < nF; ++f) {
1125           PetscInt fdof, fcdof;
1126 
1127           ierr           = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
1128           ierr           = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
1129           fieldSizes[f] += fdof-fcdof;
1130         }
1131       }
1132     }
1133     for (f = 0; f < nF; ++f) {
1134       ierr          = PetscMalloc1(fieldSizes[f], &fieldIndices[f]);CHKERRQ(ierr);
1135       fieldSizes[f] = 0;
1136     }
1137     for (p = pStart; p < pEnd; ++p) {
1138       PetscInt gdof, goff;
1139 
1140       ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1141       if (gdof > 0) {
1142         ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1143         for (f = 0; f < nF; ++f) {
1144           PetscInt fdof, fcdof, fc;
1145 
1146           ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
1147           ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
1148           for (fc = 0; fc < fdof-fcdof; ++fc, ++fieldSizes[f]) {
1149             fieldIndices[f][fieldSizes[f]] = goff++;
1150           }
1151         }
1152       }
1153     }
1154     if (numFields) *numFields = nF;
1155     if (fieldNames) {
1156       ierr = PetscMalloc1(nF, fieldNames);CHKERRQ(ierr);
1157       for (f = 0; f < nF; ++f) {
1158         const char *fieldName;
1159 
1160         ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
1161         ierr = PetscStrallocpy(fieldName, (char**) &(*fieldNames)[f]);CHKERRQ(ierr);
1162       }
1163     }
1164     if (fields) {
1165       ierr = PetscMalloc1(nF, fields);CHKERRQ(ierr);
1166       for (f = 0; f < nF; ++f) {
1167         ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), fieldSizes[f], fieldIndices[f], PETSC_OWN_POINTER, &(*fields)[f]);CHKERRQ(ierr);
1168       }
1169     }
1170     ierr = PetscFree2(fieldSizes,fieldIndices);CHKERRQ(ierr);
1171   } else if (dm->ops->createfieldis) {
1172     ierr = (*dm->ops->createfieldis)(dm, numFields, fieldNames, fields);CHKERRQ(ierr);
1173   }
1174   PetscFunctionReturn(0);
1175 }
1176 
1177 
1178 #undef __FUNCT__
1179 #define __FUNCT__ "DMCreateFieldDecomposition"
1180 /*@C
1181   DMCreateFieldDecomposition - Returns a list of IS objects defining a decomposition of a problem into subproblems
1182                           corresponding to different fields: each IS contains the global indices of the dofs of the
1183                           corresponding field. The optional list of DMs define the DM for each subproblem.
1184                           Generalizes DMCreateFieldIS().
1185 
1186   Not collective
1187 
1188   Input Parameter:
1189 . dm - the DM object
1190 
1191   Output Parameters:
1192 + len       - The number of subproblems in the field decomposition (or NULL if not requested)
1193 . namelist  - The name for each field (or NULL if not requested)
1194 . islist    - The global indices for each field (or NULL if not requested)
1195 - dmlist    - The DMs for each field subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1196 
1197   Level: intermediate
1198 
1199   Notes:
1200   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1201   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1202   and all of the arrays should be freed with PetscFree().
1203 
1204 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1205 @*/
1206 PetscErrorCode DMCreateFieldDecomposition(DM dm, PetscInt *len, char ***namelist, IS **islist, DM **dmlist)
1207 {
1208   PetscErrorCode ierr;
1209 
1210   PetscFunctionBegin;
1211   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1212   if (len) {
1213     PetscValidPointer(len,2);
1214     *len = 0;
1215   }
1216   if (namelist) {
1217     PetscValidPointer(namelist,3);
1218     *namelist = 0;
1219   }
1220   if (islist) {
1221     PetscValidPointer(islist,4);
1222     *islist = 0;
1223   }
1224   if (dmlist) {
1225     PetscValidPointer(dmlist,5);
1226     *dmlist = 0;
1227   }
1228   /*
1229    Is it a good idea to apply the following check across all impls?
1230    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1231    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1232    */
1233   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1234   if (!dm->ops->createfielddecomposition) {
1235     PetscSection section;
1236     PetscInt     numFields, f;
1237 
1238     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1239     if (section) {ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);}
1240     if (section && numFields && dm->ops->createsubdm) {
1241       *len = numFields;
1242       if (namelist) {ierr = PetscMalloc1(numFields,namelist);CHKERRQ(ierr);}
1243       if (islist)   {ierr = PetscMalloc1(numFields,islist);CHKERRQ(ierr);}
1244       if (dmlist)   {ierr = PetscMalloc1(numFields,dmlist);CHKERRQ(ierr);}
1245       for (f = 0; f < numFields; ++f) {
1246         const char *fieldName;
1247 
1248         ierr = DMCreateSubDM(dm, 1, &f, islist ? &(*islist)[f] : NULL, dmlist ? &(*dmlist)[f] : NULL);CHKERRQ(ierr);
1249         if (namelist) {
1250           ierr = PetscSectionGetFieldName(section, f, &fieldName);CHKERRQ(ierr);
1251           ierr = PetscStrallocpy(fieldName, (char**) &(*namelist)[f]);CHKERRQ(ierr);
1252         }
1253       }
1254     } else {
1255       ierr = DMCreateFieldIS(dm, len, namelist, islist);CHKERRQ(ierr);
1256       /* By default there are no DMs associated with subproblems. */
1257       if (dmlist) *dmlist = NULL;
1258     }
1259   } else {
1260     ierr = (*dm->ops->createfielddecomposition)(dm,len,namelist,islist,dmlist);CHKERRQ(ierr);
1261   }
1262   PetscFunctionReturn(0);
1263 }
1264 
1265 #undef __FUNCT__
1266 #define __FUNCT__ "DMCreateSubDM"
1267 /*@C
1268   DMCreateSubDM - Returns an IS and DM encapsulating a subproblem defined by the fields passed in.
1269                   The fields are defined by DMCreateFieldIS().
1270 
1271   Not collective
1272 
1273   Input Parameters:
1274 + dm - the DM object
1275 . numFields - number of fields in this subproblem
1276 - len       - The number of subproblems in the decomposition (or NULL if not requested)
1277 
1278   Output Parameters:
1279 . is - The global indices for the subproblem
1280 - dm - The DM for the subproblem
1281 
1282   Level: intermediate
1283 
1284 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1285 @*/
1286 PetscErrorCode DMCreateSubDM(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1287 {
1288   PetscErrorCode ierr;
1289 
1290   PetscFunctionBegin;
1291   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1292   PetscValidPointer(fields,3);
1293   if (is) PetscValidPointer(is,4);
1294   if (subdm) PetscValidPointer(subdm,5);
1295   if (dm->ops->createsubdm) {
1296     ierr = (*dm->ops->createsubdm)(dm, numFields, fields, is, subdm);CHKERRQ(ierr);
1297   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateSubDM implementation defined");
1298   PetscFunctionReturn(0);
1299 }
1300 
1301 
1302 #undef __FUNCT__
1303 #define __FUNCT__ "DMCreateDomainDecomposition"
1304 /*@C
1305   DMCreateDomainDecomposition - Returns lists of IS objects defining a decomposition of a problem into subproblems
1306                           corresponding to restrictions to pairs nested subdomains: each IS contains the global
1307                           indices of the dofs of the corresponding subdomains.  The inner subdomains conceptually
1308                           define a nonoverlapping covering, while outer subdomains can overlap.
1309                           The optional list of DMs define the DM for each subproblem.
1310 
1311   Not collective
1312 
1313   Input Parameter:
1314 . dm - the DM object
1315 
1316   Output Parameters:
1317 + len         - The number of subproblems in the domain decomposition (or NULL if not requested)
1318 . namelist    - The name for each subdomain (or NULL if not requested)
1319 . innerislist - The global indices for each inner subdomain (or NULL, if not requested)
1320 . outerislist - The global indices for each outer subdomain (or NULL, if not requested)
1321 - dmlist      - The DMs for each subdomain subproblem (or NULL, if not requested; if NULL is returned, no DMs are defined)
1322 
1323   Level: intermediate
1324 
1325   Notes:
1326   The user is responsible for freeing all requested arrays. In particular, every entry of names should be freed with
1327   PetscFree(), every entry of is should be destroyed with ISDestroy(), every entry of dm should be destroyed with DMDestroy(),
1328   and all of the arrays should be freed with PetscFree().
1329 
1330 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateDomainDecompositionDM(), DMCreateFieldDecomposition()
1331 @*/
1332 PetscErrorCode DMCreateDomainDecomposition(DM dm, PetscInt *len, char ***namelist, IS **innerislist, IS **outerislist, DM **dmlist)
1333 {
1334   PetscErrorCode      ierr;
1335   DMSubDomainHookLink link;
1336   PetscInt            i,l;
1337 
1338   PetscFunctionBegin;
1339   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1340   if (len)           {PetscValidPointer(len,2);            *len         = 0;}
1341   if (namelist)      {PetscValidPointer(namelist,3);       *namelist    = NULL;}
1342   if (innerislist)   {PetscValidPointer(innerislist,4);    *innerislist = NULL;}
1343   if (outerislist)   {PetscValidPointer(outerislist,5);    *outerislist = NULL;}
1344   if (dmlist)        {PetscValidPointer(dmlist,6);         *dmlist      = NULL;}
1345   /*
1346    Is it a good idea to apply the following check across all impls?
1347    Perhaps some impls can have a well-defined decomposition before DMSetUp?
1348    This, however, follows the general principle that accessors are not well-behaved until the object is set up.
1349    */
1350   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE, "Decomposition defined only after DMSetUp");
1351   if (dm->ops->createdomaindecomposition) {
1352     ierr = (*dm->ops->createdomaindecomposition)(dm,&l,namelist,innerislist,outerislist,dmlist);CHKERRQ(ierr);
1353     /* copy subdomain hooks and context over to the subdomain DMs */
1354     if (dmlist) {
1355       for (i = 0; i < l; i++) {
1356         for (link=dm->subdomainhook; link; link=link->next) {
1357           if (link->ddhook) {ierr = (*link->ddhook)(dm,(*dmlist)[i],link->ctx);CHKERRQ(ierr);}
1358         }
1359         (*dmlist)[i]->ctx = dm->ctx;
1360       }
1361     }
1362     if (len) *len = l;
1363   }
1364   PetscFunctionReturn(0);
1365 }
1366 
1367 
1368 #undef __FUNCT__
1369 #define __FUNCT__ "DMCreateDomainDecompositionScatters"
1370 /*@C
1371   DMCreateDomainDecompositionScatters - Returns scatters to the subdomain vectors from the global vector
1372 
1373   Not collective
1374 
1375   Input Parameters:
1376 + dm - the DM object
1377 . n  - the number of subdomain scatters
1378 - subdms - the local subdomains
1379 
1380   Output Parameters:
1381 + n     - the number of scatters returned
1382 . iscat - scatter from global vector to nonoverlapping global vector entries on subdomain
1383 . oscat - scatter from global vector to overlapping global vector entries on subdomain
1384 - gscat - scatter from global vector to local vector on subdomain (fills in ghosts)
1385 
1386   Notes: This is an alternative to the iis and ois arguments in DMCreateDomainDecomposition that allow for the solution
1387   of general nonlinear problems with overlapping subdomain methods.  While merely having index sets that enable subsets
1388   of the residual equations to be created is fine for linear problems, nonlinear problems require local assembly of
1389   solution and residual data.
1390 
1391   Level: developer
1392 
1393 .seealso DMDestroy(), DMView(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMCreateFieldIS()
1394 @*/
1395 PetscErrorCode DMCreateDomainDecompositionScatters(DM dm,PetscInt n,DM *subdms,VecScatter **iscat,VecScatter **oscat,VecScatter **gscat)
1396 {
1397   PetscErrorCode ierr;
1398 
1399   PetscFunctionBegin;
1400   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1401   PetscValidPointer(subdms,3);
1402   if (dm->ops->createddscatters) {
1403     ierr = (*dm->ops->createddscatters)(dm,n,subdms,iscat,oscat,gscat);CHKERRQ(ierr);
1404   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "This type has no DMCreateDomainDecompositionLocalScatter implementation defined");
1405   PetscFunctionReturn(0);
1406 }
1407 
1408 #undef __FUNCT__
1409 #define __FUNCT__ "DMRefine"
1410 /*@
1411   DMRefine - Refines a DM object
1412 
1413   Collective on DM
1414 
1415   Input Parameter:
1416 + dm   - the DM object
1417 - comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
1418 
1419   Output Parameter:
1420 . dmf - the refined DM, or NULL
1421 
1422   Note: If no refinement was done, the return value is NULL
1423 
1424   Level: developer
1425 
1426 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1427 @*/
1428 PetscErrorCode  DMRefine(DM dm,MPI_Comm comm,DM *dmf)
1429 {
1430   PetscErrorCode   ierr;
1431   DMRefineHookLink link;
1432 
1433   PetscFunctionBegin;
1434   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1435   ierr = (*dm->ops->refine)(dm,comm,dmf);CHKERRQ(ierr);
1436   if (*dmf) {
1437     (*dmf)->ops->creatematrix = dm->ops->creatematrix;
1438 
1439     ierr = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmf);CHKERRQ(ierr);
1440 
1441     (*dmf)->ctx       = dm->ctx;
1442     (*dmf)->leveldown = dm->leveldown;
1443     (*dmf)->levelup   = dm->levelup + 1;
1444 
1445     ierr = DMSetMatType(*dmf,dm->mattype);CHKERRQ(ierr);
1446     for (link=dm->refinehook; link; link=link->next) {
1447       if (link->refinehook) {
1448         ierr = (*link->refinehook)(dm,*dmf,link->ctx);CHKERRQ(ierr);
1449       }
1450     }
1451   }
1452   PetscFunctionReturn(0);
1453 }
1454 
1455 #undef __FUNCT__
1456 #define __FUNCT__ "DMRefineHookAdd"
1457 /*@C
1458    DMRefineHookAdd - adds a callback to be run when interpolating a nonlinear problem to a finer grid
1459 
1460    Logically Collective
1461 
1462    Input Arguments:
1463 +  coarse - nonlinear solver context on which to run a hook when restricting to a coarser level
1464 .  refinehook - function to run when setting up a coarser level
1465 .  interphook - function to run to update data on finer levels (once per SNESSolve())
1466 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1467 
1468    Calling sequence of refinehook:
1469 $    refinehook(DM coarse,DM fine,void *ctx);
1470 
1471 +  coarse - coarse level DM
1472 .  fine - fine level DM to interpolate problem to
1473 -  ctx - optional user-defined function context
1474 
1475    Calling sequence for interphook:
1476 $    interphook(DM coarse,Mat interp,DM fine,void *ctx)
1477 
1478 +  coarse - coarse level DM
1479 .  interp - matrix interpolating a coarse-level solution to the finer grid
1480 .  fine - fine level DM to update
1481 -  ctx - optional user-defined function context
1482 
1483    Level: advanced
1484 
1485    Notes:
1486    This function is only needed if auxiliary data needs to be passed to fine grids while grid sequencing
1487 
1488    If this function is called multiple times, the hooks will be run in the order they are added.
1489 
1490    This function is currently not available from Fortran.
1491 
1492 .seealso: DMCoarsenHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1493 @*/
1494 PetscErrorCode DMRefineHookAdd(DM coarse,PetscErrorCode (*refinehook)(DM,DM,void*),PetscErrorCode (*interphook)(DM,Mat,DM,void*),void *ctx)
1495 {
1496   PetscErrorCode   ierr;
1497   DMRefineHookLink link,*p;
1498 
1499   PetscFunctionBegin;
1500   PetscValidHeaderSpecific(coarse,DM_CLASSID,1);
1501   for (p=&coarse->refinehook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1502   ierr             = PetscMalloc(sizeof(struct _DMRefineHookLink),&link);CHKERRQ(ierr);
1503   link->refinehook = refinehook;
1504   link->interphook = interphook;
1505   link->ctx        = ctx;
1506   link->next       = NULL;
1507   *p               = link;
1508   PetscFunctionReturn(0);
1509 }
1510 
1511 #undef __FUNCT__
1512 #define __FUNCT__ "DMInterpolate"
1513 /*@
1514    DMInterpolate - interpolates user-defined problem data to a finer DM by running hooks registered by DMRefineHookAdd()
1515 
1516    Collective if any hooks are
1517 
1518    Input Arguments:
1519 +  coarse - coarser DM to use as a base
1520 .  restrct - interpolation matrix, apply using MatInterpolate()
1521 -  fine - finer DM to update
1522 
1523    Level: developer
1524 
1525 .seealso: DMRefineHookAdd(), MatInterpolate()
1526 @*/
1527 PetscErrorCode DMInterpolate(DM coarse,Mat interp,DM fine)
1528 {
1529   PetscErrorCode   ierr;
1530   DMRefineHookLink link;
1531 
1532   PetscFunctionBegin;
1533   for (link=fine->refinehook; link; link=link->next) {
1534     if (link->interphook) {
1535       ierr = (*link->interphook)(coarse,interp,fine,link->ctx);CHKERRQ(ierr);
1536     }
1537   }
1538   PetscFunctionReturn(0);
1539 }
1540 
1541 #undef __FUNCT__
1542 #define __FUNCT__ "DMGetRefineLevel"
1543 /*@
1544     DMGetRefineLevel - Get's the number of refinements that have generated this DM.
1545 
1546     Not Collective
1547 
1548     Input Parameter:
1549 .   dm - the DM object
1550 
1551     Output Parameter:
1552 .   level - number of refinements
1553 
1554     Level: developer
1555 
1556 .seealso DMCoarsen(), DMGetCoarsenLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1557 
1558 @*/
1559 PetscErrorCode  DMGetRefineLevel(DM dm,PetscInt *level)
1560 {
1561   PetscFunctionBegin;
1562   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1563   *level = dm->levelup;
1564   PetscFunctionReturn(0);
1565 }
1566 
1567 #undef __FUNCT__
1568 #define __FUNCT__ "DMGlobalToLocalHookAdd"
1569 /*@C
1570    DMGlobalToLocalHookAdd - adds a callback to be run when global to local is called
1571 
1572    Logically Collective
1573 
1574    Input Arguments:
1575 +  dm - the DM
1576 .  beginhook - function to run at the beginning of DMGlobalToLocalBegin()
1577 .  endhook - function to run after DMGlobalToLocalEnd() has completed
1578 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1579 
1580    Calling sequence for beginhook:
1581 $    beginhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
1582 
1583 +  dm - global DM
1584 .  g - global vector
1585 .  mode - mode
1586 .  l - local vector
1587 -  ctx - optional user-defined function context
1588 
1589 
1590    Calling sequence for endhook:
1591 $    endhook(DM fine,VecScatter out,VecScatter in,DM coarse,void *ctx)
1592 
1593 +  global - global DM
1594 -  ctx - optional user-defined function context
1595 
1596    Level: advanced
1597 
1598 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1599 @*/
1600 PetscErrorCode DMGlobalToLocalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
1601 {
1602   PetscErrorCode          ierr;
1603   DMGlobalToLocalHookLink link,*p;
1604 
1605   PetscFunctionBegin;
1606   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1607   for (p=&dm->gtolhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1608   ierr            = PetscMalloc(sizeof(struct _DMGlobalToLocalHookLink),&link);CHKERRQ(ierr);
1609   link->beginhook = beginhook;
1610   link->endhook   = endhook;
1611   link->ctx       = ctx;
1612   link->next      = NULL;
1613   *p              = link;
1614   PetscFunctionReturn(0);
1615 }
1616 
1617 #undef __FUNCT__
1618 #define __FUNCT__ "DMGlobalToLocalBegin"
1619 /*@
1620     DMGlobalToLocalBegin - Begins updating local vectors from global vector
1621 
1622     Neighbor-wise Collective on DM
1623 
1624     Input Parameters:
1625 +   dm - the DM object
1626 .   g - the global vector
1627 .   mode - INSERT_VALUES or ADD_VALUES
1628 -   l - the local vector
1629 
1630 
1631     Level: beginner
1632 
1633 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1634 
1635 @*/
1636 PetscErrorCode  DMGlobalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
1637 {
1638   PetscSF                 sf;
1639   PetscErrorCode          ierr;
1640   DMGlobalToLocalHookLink link;
1641 
1642   PetscFunctionBegin;
1643   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1644   for (link=dm->gtolhook; link; link=link->next) {
1645     if (link->beginhook) {
1646       ierr = (*link->beginhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);
1647     }
1648   }
1649   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1650   if (sf) {
1651     PetscScalar *lArray, *gArray;
1652 
1653     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1654     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1655     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1656     ierr = PetscSFBcastBegin(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
1657     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1658     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1659   } else {
1660     ierr = (*dm->ops->globaltolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1661   }
1662   PetscFunctionReturn(0);
1663 }
1664 
1665 #undef __FUNCT__
1666 #define __FUNCT__ "DMGlobalToLocalEnd"
1667 /*@
1668     DMGlobalToLocalEnd - Ends updating local vectors from global vector
1669 
1670     Neighbor-wise Collective on DM
1671 
1672     Input Parameters:
1673 +   dm - the DM object
1674 .   g - the global vector
1675 .   mode - INSERT_VALUES or ADD_VALUES
1676 -   l - the local vector
1677 
1678 
1679     Level: beginner
1680 
1681 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1682 
1683 @*/
1684 PetscErrorCode  DMGlobalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
1685 {
1686   PetscSF                 sf;
1687   PetscErrorCode          ierr;
1688   PetscScalar             *lArray, *gArray;
1689   DMGlobalToLocalHookLink link;
1690 
1691   PetscFunctionBegin;
1692   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1693   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1694   if (sf) {
1695     if (mode == ADD_VALUES) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1696 
1697     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1698     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1699     ierr = PetscSFBcastEnd(sf, MPIU_SCALAR, gArray, lArray);CHKERRQ(ierr);
1700     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1701     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1702   } else {
1703     ierr = (*dm->ops->globaltolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1704   }
1705   for (link=dm->gtolhook; link; link=link->next) {
1706     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
1707   }
1708   PetscFunctionReturn(0);
1709 }
1710 
1711 #undef __FUNCT__
1712 #define __FUNCT__ "DMLocalToGlobalHookAdd"
1713 /*@C
1714    DMLocalToGlobalHookAdd - adds a callback to be run when a local to global is called
1715 
1716    Logically Collective
1717 
1718    Input Arguments:
1719 +  dm - the DM
1720 .  beginhook - function to run at the beginning of DMLocalToGlobalBegin()
1721 .  endhook - function to run after DMLocalToGlobalEnd() has completed
1722 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
1723 
1724    Calling sequence for beginhook:
1725 $    beginhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
1726 
1727 +  dm - global DM
1728 .  l - local vector
1729 .  mode - mode
1730 .  g - global vector
1731 -  ctx - optional user-defined function context
1732 
1733 
1734    Calling sequence for endhook:
1735 $    endhook(DM fine,Vec l,InsertMode mode,Vec g,void *ctx)
1736 
1737 +  global - global DM
1738 .  l - local vector
1739 .  mode - mode
1740 .  g - global vector
1741 -  ctx - optional user-defined function context
1742 
1743    Level: advanced
1744 
1745 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
1746 @*/
1747 PetscErrorCode DMLocalToGlobalHookAdd(DM dm,PetscErrorCode (*beginhook)(DM,Vec,InsertMode,Vec,void*),PetscErrorCode (*endhook)(DM,Vec,InsertMode,Vec,void*),void *ctx)
1748 {
1749   PetscErrorCode          ierr;
1750   DMLocalToGlobalHookLink link,*p;
1751 
1752   PetscFunctionBegin;
1753   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1754   for (p=&dm->ltoghook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
1755   ierr            = PetscMalloc(sizeof(struct _DMLocalToGlobalHookLink),&link);CHKERRQ(ierr);
1756   link->beginhook = beginhook;
1757   link->endhook   = endhook;
1758   link->ctx       = ctx;
1759   link->next      = NULL;
1760   *p              = link;
1761   PetscFunctionReturn(0);
1762 }
1763 
1764 #undef __FUNCT__
1765 #define __FUNCT__ "DMLocalToGlobalBegin"
1766 /*@
1767     DMLocalToGlobalBegin - updates global vectors from local vectors
1768 
1769     Neighbor-wise Collective on DM
1770 
1771     Input Parameters:
1772 +   dm - the DM object
1773 .   l - the local vector
1774 .   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
1775            base point.
1776 - - the global vector
1777 
1778     Notes: In the ADD_VALUES case you normally would zero the receiving vector before beginning this operation. If you would like to simply add the non-ghosted values in the local
1779            array into the global array you need to either (1) zero the ghosted locations and use ADD_VALUES or (2) use INSERT_VALUES into a work global array and then add the work
1780            global array to the final global array with VecAXPY().
1781 
1782     Level: beginner
1783 
1784 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalBegin()
1785 
1786 @*/
1787 PetscErrorCode  DMLocalToGlobalBegin(DM dm,Vec l,InsertMode mode,Vec g)
1788 {
1789   PetscSF                 sf;
1790   PetscErrorCode          ierr;
1791   DMLocalToGlobalHookLink link;
1792 
1793   PetscFunctionBegin;
1794   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1795   for (link=dm->ltoghook; link; link=link->next) {
1796     if (link->beginhook) {
1797       ierr = (*link->beginhook)(dm,l,mode,g,link->ctx);CHKERRQ(ierr);
1798     }
1799   }
1800   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1801   if (sf) {
1802     MPI_Op      op;
1803     PetscScalar *lArray, *gArray;
1804 
1805     switch (mode) {
1806     case INSERT_VALUES:
1807     case INSERT_ALL_VALUES:
1808       op = MPIU_REPLACE; break;
1809     case ADD_VALUES:
1810     case ADD_ALL_VALUES:
1811       op = MPI_SUM; break;
1812     default:
1813       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1814     }
1815     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1816     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1817     ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, op);CHKERRQ(ierr);
1818     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1819     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1820   } else {
1821     ierr = (*dm->ops->localtoglobalbegin)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
1822   }
1823   PetscFunctionReturn(0);
1824 }
1825 
1826 #undef __FUNCT__
1827 #define __FUNCT__ "DMLocalToGlobalEnd"
1828 /*@
1829     DMLocalToGlobalEnd - updates global vectors from local vectors
1830 
1831     Neighbor-wise Collective on DM
1832 
1833     Input Parameters:
1834 +   dm - the DM object
1835 .   l - the local vector
1836 .   mode - INSERT_VALUES or ADD_VALUES
1837 -   g - the global vector
1838 
1839 
1840     Level: beginner
1841 
1842 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMGlobalToLocalEnd(), DMGlobalToLocalEnd()
1843 
1844 @*/
1845 PetscErrorCode  DMLocalToGlobalEnd(DM dm,Vec l,InsertMode mode,Vec g)
1846 {
1847   PetscSF        sf;
1848   PetscErrorCode ierr;
1849   DMLocalToGlobalHookLink link;
1850 
1851   PetscFunctionBegin;
1852   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1853   ierr = DMGetDefaultSF(dm, &sf);CHKERRQ(ierr);
1854   if (sf) {
1855     MPI_Op      op;
1856     PetscScalar *lArray, *gArray;
1857 
1858     switch (mode) {
1859     case INSERT_VALUES:
1860     case INSERT_ALL_VALUES:
1861       op = MPIU_REPLACE; break;
1862     case ADD_VALUES:
1863     case ADD_ALL_VALUES:
1864       op = MPI_SUM; break;
1865     default:
1866       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insertion mode %D", mode);
1867     }
1868     ierr = VecGetArray(l, &lArray);CHKERRQ(ierr);
1869     ierr = VecGetArray(g, &gArray);CHKERRQ(ierr);
1870     ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, op);CHKERRQ(ierr);
1871     ierr = VecRestoreArray(l, &lArray);CHKERRQ(ierr);
1872     ierr = VecRestoreArray(g, &gArray);CHKERRQ(ierr);
1873   } else {
1874     ierr = (*dm->ops->localtoglobalend)(dm,l,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),g);CHKERRQ(ierr);
1875   }
1876   for (link=dm->ltoghook; link; link=link->next) {
1877     if (link->endhook) {ierr = (*link->endhook)(dm,g,mode,l,link->ctx);CHKERRQ(ierr);}
1878   }
1879   PetscFunctionReturn(0);
1880 }
1881 
1882 #undef __FUNCT__
1883 #define __FUNCT__ "DMLocalToLocalBegin"
1884 /*@
1885    DMLocalToLocalBegin - Maps from a local vector (including ghost points
1886    that contain irrelevant values) to another local vector where the ghost
1887    points in the second are set correctly. Must be followed by DMLocalToLocalEnd().
1888 
1889    Neighbor-wise Collective on DM and Vec
1890 
1891    Input Parameters:
1892 +  dm - the DM object
1893 .  g - the original local vector
1894 -  mode - one of INSERT_VALUES or ADD_VALUES
1895 
1896    Output Parameter:
1897 .  l  - the local vector with correct ghost values
1898 
1899    Level: intermediate
1900 
1901    Notes:
1902    The local vectors used here need not be the same as those
1903    obtained from DMCreateLocalVector(), BUT they
1904    must have the same parallel data layout; they could, for example, be
1905    obtained with VecDuplicate() from the DM originating vectors.
1906 
1907 .keywords: DM, local-to-local, begin
1908 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalEnd(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1909 
1910 @*/
1911 PetscErrorCode  DMLocalToLocalBegin(DM dm,Vec g,InsertMode mode,Vec l)
1912 {
1913   PetscErrorCode          ierr;
1914 
1915   PetscFunctionBegin;
1916   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1917   ierr = (*dm->ops->localtolocalbegin)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1918   PetscFunctionReturn(0);
1919 }
1920 
1921 #undef __FUNCT__
1922 #define __FUNCT__ "DMLocalToLocalEnd"
1923 /*@
1924    DMLocalToLocalEnd - Maps from a local vector (including ghost points
1925    that contain irrelevant values) to another local vector where the ghost
1926    points in the second are set correctly. Must be preceded by DMLocalToLocalBegin().
1927 
1928    Neighbor-wise Collective on DM and Vec
1929 
1930    Input Parameters:
1931 +  da - the DM object
1932 .  g - the original local vector
1933 -  mode - one of INSERT_VALUES or ADD_VALUES
1934 
1935    Output Parameter:
1936 .  l  - the local vector with correct ghost values
1937 
1938    Level: intermediate
1939 
1940    Notes:
1941    The local vectors used here need not be the same as those
1942    obtained from DMCreateLocalVector(), BUT they
1943    must have the same parallel data layout; they could, for example, be
1944    obtained with VecDuplicate() from the DM originating vectors.
1945 
1946 .keywords: DM, local-to-local, end
1947 .seealso DMCoarsen(), DMDestroy(), DMView(), DMCreateLocalVector(), DMCreateGlobalVector(), DMCreateInterpolation(), DMLocalToLocalBegin(), DMGlobalToLocalEnd(), DMLocalToGlobalBegin()
1948 
1949 @*/
1950 PetscErrorCode  DMLocalToLocalEnd(DM dm,Vec g,InsertMode mode,Vec l)
1951 {
1952   PetscErrorCode          ierr;
1953 
1954   PetscFunctionBegin;
1955   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1956   ierr = (*dm->ops->localtolocalend)(dm,g,mode == INSERT_ALL_VALUES ? INSERT_VALUES : (mode == ADD_ALL_VALUES ? ADD_VALUES : mode),l);CHKERRQ(ierr);
1957   PetscFunctionReturn(0);
1958 }
1959 
1960 
1961 #undef __FUNCT__
1962 #define __FUNCT__ "DMCoarsen"
1963 /*@
1964     DMCoarsen - Coarsens a DM object
1965 
1966     Collective on DM
1967 
1968     Input Parameter:
1969 +   dm - the DM object
1970 -   comm - the communicator to contain the new DM object (or MPI_COMM_NULL)
1971 
1972     Output Parameter:
1973 .   dmc - the coarsened DM
1974 
1975     Level: developer
1976 
1977 .seealso DMRefine(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
1978 
1979 @*/
1980 PetscErrorCode  DMCoarsen(DM dm, MPI_Comm comm, DM *dmc)
1981 {
1982   PetscErrorCode    ierr;
1983   DMCoarsenHookLink link;
1984 
1985   PetscFunctionBegin;
1986   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
1987   ierr                      = (*dm->ops->coarsen)(dm, comm, dmc);CHKERRQ(ierr);
1988   (*dmc)->ops->creatematrix = dm->ops->creatematrix;
1989   ierr                      = PetscObjectCopyFortranFunctionPointers((PetscObject)dm,(PetscObject)*dmc);CHKERRQ(ierr);
1990   (*dmc)->ctx               = dm->ctx;
1991   (*dmc)->levelup           = dm->levelup;
1992   (*dmc)->leveldown         = dm->leveldown + 1;
1993   ierr                      = DMSetMatType(*dmc,dm->mattype);CHKERRQ(ierr);
1994   for (link=dm->coarsenhook; link; link=link->next) {
1995     if (link->coarsenhook) {ierr = (*link->coarsenhook)(dm,*dmc,link->ctx);CHKERRQ(ierr);}
1996   }
1997   PetscFunctionReturn(0);
1998 }
1999 
2000 #undef __FUNCT__
2001 #define __FUNCT__ "DMCoarsenHookAdd"
2002 /*@C
2003    DMCoarsenHookAdd - adds a callback to be run when restricting a nonlinear problem to the coarse grid
2004 
2005    Logically Collective
2006 
2007    Input Arguments:
2008 +  fine - nonlinear solver context on which to run a hook when restricting to a coarser level
2009 .  coarsenhook - function to run when setting up a coarser level
2010 .  restricthook - function to run to update data on coarser levels (once per SNESSolve())
2011 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2012 
2013    Calling sequence of coarsenhook:
2014 $    coarsenhook(DM fine,DM coarse,void *ctx);
2015 
2016 +  fine - fine level DM
2017 .  coarse - coarse level DM to restrict problem to
2018 -  ctx - optional user-defined function context
2019 
2020    Calling sequence for restricthook:
2021 $    restricthook(DM fine,Mat mrestrict,Vec rscale,Mat inject,DM coarse,void *ctx)
2022 
2023 +  fine - fine level DM
2024 .  mrestrict - matrix restricting a fine-level solution to the coarse grid
2025 .  rscale - scaling vector for restriction
2026 .  inject - matrix restricting by injection
2027 .  coarse - coarse level DM to update
2028 -  ctx - optional user-defined function context
2029 
2030    Level: advanced
2031 
2032    Notes:
2033    This function is only needed if auxiliary data needs to be set up on coarse grids.
2034 
2035    If this function is called multiple times, the hooks will be run in the order they are added.
2036 
2037    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2038    extract the finest level information from its context (instead of from the SNES).
2039 
2040    This function is currently not available from Fortran.
2041 
2042 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2043 @*/
2044 PetscErrorCode DMCoarsenHookAdd(DM fine,PetscErrorCode (*coarsenhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,Mat,Vec,Mat,DM,void*),void *ctx)
2045 {
2046   PetscErrorCode    ierr;
2047   DMCoarsenHookLink link,*p;
2048 
2049   PetscFunctionBegin;
2050   PetscValidHeaderSpecific(fine,DM_CLASSID,1);
2051   for (p=&fine->coarsenhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2052   ierr               = PetscMalloc(sizeof(struct _DMCoarsenHookLink),&link);CHKERRQ(ierr);
2053   link->coarsenhook  = coarsenhook;
2054   link->restricthook = restricthook;
2055   link->ctx          = ctx;
2056   link->next         = NULL;
2057   *p                 = link;
2058   PetscFunctionReturn(0);
2059 }
2060 
2061 #undef __FUNCT__
2062 #define __FUNCT__ "DMRestrict"
2063 /*@
2064    DMRestrict - restricts user-defined problem data to a coarser DM by running hooks registered by DMCoarsenHookAdd()
2065 
2066    Collective if any hooks are
2067 
2068    Input Arguments:
2069 +  fine - finer DM to use as a base
2070 .  restrct - restriction matrix, apply using MatRestrict()
2071 .  inject - injection matrix, also use MatRestrict()
2072 -  coarse - coarer DM to update
2073 
2074    Level: developer
2075 
2076 .seealso: DMCoarsenHookAdd(), MatRestrict()
2077 @*/
2078 PetscErrorCode DMRestrict(DM fine,Mat restrct,Vec rscale,Mat inject,DM coarse)
2079 {
2080   PetscErrorCode    ierr;
2081   DMCoarsenHookLink link;
2082 
2083   PetscFunctionBegin;
2084   for (link=fine->coarsenhook; link; link=link->next) {
2085     if (link->restricthook) {
2086       ierr = (*link->restricthook)(fine,restrct,rscale,inject,coarse,link->ctx);CHKERRQ(ierr);
2087     }
2088   }
2089   PetscFunctionReturn(0);
2090 }
2091 
2092 #undef __FUNCT__
2093 #define __FUNCT__ "DMSubDomainHookAdd"
2094 /*@C
2095    DMSubDomainHookAdd - adds a callback to be run when restricting a problem to the coarse grid
2096 
2097    Logically Collective
2098 
2099    Input Arguments:
2100 +  global - global DM
2101 .  ddhook - function to run to pass data to the decomposition DM upon its creation
2102 .  restricthook - function to run to update data on block solve (at the beginning of the block solve)
2103 -  ctx - [optional] user-defined context for provide data for the hooks (may be NULL)
2104 
2105 
2106    Calling sequence for ddhook:
2107 $    ddhook(DM global,DM block,void *ctx)
2108 
2109 +  global - global DM
2110 .  block  - block DM
2111 -  ctx - optional user-defined function context
2112 
2113    Calling sequence for restricthook:
2114 $    restricthook(DM global,VecScatter out,VecScatter in,DM block,void *ctx)
2115 
2116 +  global - global DM
2117 .  out    - scatter to the outer (with ghost and overlap points) block vector
2118 .  in     - scatter to block vector values only owned locally
2119 .  block  - block DM
2120 -  ctx - optional user-defined function context
2121 
2122    Level: advanced
2123 
2124    Notes:
2125    This function is only needed if auxiliary data needs to be set up on subdomain DMs.
2126 
2127    If this function is called multiple times, the hooks will be run in the order they are added.
2128 
2129    In order to compose with nonlinear preconditioning without duplicating storage, the hook should be implemented to
2130    extract the global information from its context (instead of from the SNES).
2131 
2132    This function is currently not available from Fortran.
2133 
2134 .seealso: DMRefineHookAdd(), SNESFASGetInterpolation(), SNESFASGetInjection(), PetscObjectCompose(), PetscContainerCreate()
2135 @*/
2136 PetscErrorCode DMSubDomainHookAdd(DM global,PetscErrorCode (*ddhook)(DM,DM,void*),PetscErrorCode (*restricthook)(DM,VecScatter,VecScatter,DM,void*),void *ctx)
2137 {
2138   PetscErrorCode      ierr;
2139   DMSubDomainHookLink link,*p;
2140 
2141   PetscFunctionBegin;
2142   PetscValidHeaderSpecific(global,DM_CLASSID,1);
2143   for (p=&global->subdomainhook; *p; p=&(*p)->next) {} /* Scan to the end of the current list of hooks */
2144   ierr               = PetscMalloc(sizeof(struct _DMSubDomainHookLink),&link);CHKERRQ(ierr);
2145   link->restricthook = restricthook;
2146   link->ddhook       = ddhook;
2147   link->ctx          = ctx;
2148   link->next         = NULL;
2149   *p                 = link;
2150   PetscFunctionReturn(0);
2151 }
2152 
2153 #undef __FUNCT__
2154 #define __FUNCT__ "DMSubDomainRestrict"
2155 /*@
2156    DMSubDomainRestrict - restricts user-defined problem data to a block DM by running hooks registered by DMSubDomainHookAdd()
2157 
2158    Collective if any hooks are
2159 
2160    Input Arguments:
2161 +  fine - finer DM to use as a base
2162 .  oscatter - scatter from domain global vector filling subdomain global vector with overlap
2163 .  gscatter - scatter from domain global vector filling subdomain local vector with ghosts
2164 -  coarse - coarer DM to update
2165 
2166    Level: developer
2167 
2168 .seealso: DMCoarsenHookAdd(), MatRestrict()
2169 @*/
2170 PetscErrorCode DMSubDomainRestrict(DM global,VecScatter oscatter,VecScatter gscatter,DM subdm)
2171 {
2172   PetscErrorCode      ierr;
2173   DMSubDomainHookLink link;
2174 
2175   PetscFunctionBegin;
2176   for (link=global->subdomainhook; link; link=link->next) {
2177     if (link->restricthook) {
2178       ierr = (*link->restricthook)(global,oscatter,gscatter,subdm,link->ctx);CHKERRQ(ierr);
2179     }
2180   }
2181   PetscFunctionReturn(0);
2182 }
2183 
2184 #undef __FUNCT__
2185 #define __FUNCT__ "DMGetCoarsenLevel"
2186 /*@
2187     DMGetCoarsenLevel - Get's the number of coarsenings that have generated this DM.
2188 
2189     Not Collective
2190 
2191     Input Parameter:
2192 .   dm - the DM object
2193 
2194     Output Parameter:
2195 .   level - number of coarsenings
2196 
2197     Level: developer
2198 
2199 .seealso DMCoarsen(), DMGetRefineLevel(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2200 
2201 @*/
2202 PetscErrorCode  DMGetCoarsenLevel(DM dm,PetscInt *level)
2203 {
2204   PetscFunctionBegin;
2205   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2206   *level = dm->leveldown;
2207   PetscFunctionReturn(0);
2208 }
2209 
2210 
2211 
2212 #undef __FUNCT__
2213 #define __FUNCT__ "DMRefineHierarchy"
2214 /*@C
2215     DMRefineHierarchy - Refines a DM object, all levels at once
2216 
2217     Collective on DM
2218 
2219     Input Parameter:
2220 +   dm - the DM object
2221 -   nlevels - the number of levels of refinement
2222 
2223     Output Parameter:
2224 .   dmf - the refined DM hierarchy
2225 
2226     Level: developer
2227 
2228 .seealso DMCoarsenHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2229 
2230 @*/
2231 PetscErrorCode  DMRefineHierarchy(DM dm,PetscInt nlevels,DM dmf[])
2232 {
2233   PetscErrorCode ierr;
2234 
2235   PetscFunctionBegin;
2236   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2237   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2238   if (nlevels == 0) PetscFunctionReturn(0);
2239   if (dm->ops->refinehierarchy) {
2240     ierr = (*dm->ops->refinehierarchy)(dm,nlevels,dmf);CHKERRQ(ierr);
2241   } else if (dm->ops->refine) {
2242     PetscInt i;
2243 
2244     ierr = DMRefine(dm,PetscObjectComm((PetscObject)dm),&dmf[0]);CHKERRQ(ierr);
2245     for (i=1; i<nlevels; i++) {
2246       ierr = DMRefine(dmf[i-1],PetscObjectComm((PetscObject)dm),&dmf[i]);CHKERRQ(ierr);
2247     }
2248   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No RefineHierarchy for this DM yet");
2249   PetscFunctionReturn(0);
2250 }
2251 
2252 #undef __FUNCT__
2253 #define __FUNCT__ "DMCoarsenHierarchy"
2254 /*@C
2255     DMCoarsenHierarchy - Coarsens a DM object, all levels at once
2256 
2257     Collective on DM
2258 
2259     Input Parameter:
2260 +   dm - the DM object
2261 -   nlevels - the number of levels of coarsening
2262 
2263     Output Parameter:
2264 .   dmc - the coarsened DM hierarchy
2265 
2266     Level: developer
2267 
2268 .seealso DMRefineHierarchy(), DMDestroy(), DMView(), DMCreateGlobalVector(), DMCreateInterpolation()
2269 
2270 @*/
2271 PetscErrorCode  DMCoarsenHierarchy(DM dm, PetscInt nlevels, DM dmc[])
2272 {
2273   PetscErrorCode ierr;
2274 
2275   PetscFunctionBegin;
2276   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2277   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
2278   if (nlevels == 0) PetscFunctionReturn(0);
2279   PetscValidPointer(dmc,3);
2280   if (dm->ops->coarsenhierarchy) {
2281     ierr = (*dm->ops->coarsenhierarchy)(dm, nlevels, dmc);CHKERRQ(ierr);
2282   } else if (dm->ops->coarsen) {
2283     PetscInt i;
2284 
2285     ierr = DMCoarsen(dm,PetscObjectComm((PetscObject)dm),&dmc[0]);CHKERRQ(ierr);
2286     for (i=1; i<nlevels; i++) {
2287       ierr = DMCoarsen(dmc[i-1],PetscObjectComm((PetscObject)dm),&dmc[i]);CHKERRQ(ierr);
2288     }
2289   } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"No CoarsenHierarchy for this DM yet");
2290   PetscFunctionReturn(0);
2291 }
2292 
2293 #undef __FUNCT__
2294 #define __FUNCT__ "DMCreateAggregates"
2295 /*@
2296    DMCreateAggregates - Gets the aggregates that map between
2297    grids associated with two DMs.
2298 
2299    Collective on DM
2300 
2301    Input Parameters:
2302 +  dmc - the coarse grid DM
2303 -  dmf - the fine grid DM
2304 
2305    Output Parameters:
2306 .  rest - the restriction matrix (transpose of the projection matrix)
2307 
2308    Level: intermediate
2309 
2310 .keywords: interpolation, restriction, multigrid
2311 
2312 .seealso: DMRefine(), DMCreateInjection(), DMCreateInterpolation()
2313 @*/
2314 PetscErrorCode  DMCreateAggregates(DM dmc, DM dmf, Mat *rest)
2315 {
2316   PetscErrorCode ierr;
2317 
2318   PetscFunctionBegin;
2319   PetscValidHeaderSpecific(dmc,DM_CLASSID,1);
2320   PetscValidHeaderSpecific(dmf,DM_CLASSID,2);
2321   ierr = (*dmc->ops->getaggregates)(dmc, dmf, rest);CHKERRQ(ierr);
2322   PetscFunctionReturn(0);
2323 }
2324 
2325 #undef __FUNCT__
2326 #define __FUNCT__ "DMSetApplicationContextDestroy"
2327 /*@C
2328     DMSetApplicationContextDestroy - Sets a user function that will be called to destroy the application context when the DM is destroyed
2329 
2330     Not Collective
2331 
2332     Input Parameters:
2333 +   dm - the DM object
2334 -   destroy - the destroy function
2335 
2336     Level: intermediate
2337 
2338 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2339 
2340 @*/
2341 PetscErrorCode  DMSetApplicationContextDestroy(DM dm,PetscErrorCode (*destroy)(void**))
2342 {
2343   PetscFunctionBegin;
2344   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2345   dm->ctxdestroy = destroy;
2346   PetscFunctionReturn(0);
2347 }
2348 
2349 #undef __FUNCT__
2350 #define __FUNCT__ "DMSetApplicationContext"
2351 /*@
2352     DMSetApplicationContext - Set a user context into a DM object
2353 
2354     Not Collective
2355 
2356     Input Parameters:
2357 +   dm - the DM object
2358 -   ctx - the user context
2359 
2360     Level: intermediate
2361 
2362 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2363 
2364 @*/
2365 PetscErrorCode  DMSetApplicationContext(DM dm,void *ctx)
2366 {
2367   PetscFunctionBegin;
2368   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2369   dm->ctx = ctx;
2370   PetscFunctionReturn(0);
2371 }
2372 
2373 #undef __FUNCT__
2374 #define __FUNCT__ "DMGetApplicationContext"
2375 /*@
2376     DMGetApplicationContext - Gets a user context from a DM object
2377 
2378     Not Collective
2379 
2380     Input Parameter:
2381 .   dm - the DM object
2382 
2383     Output Parameter:
2384 .   ctx - the user context
2385 
2386     Level: intermediate
2387 
2388 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2389 
2390 @*/
2391 PetscErrorCode  DMGetApplicationContext(DM dm,void *ctx)
2392 {
2393   PetscFunctionBegin;
2394   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2395   *(void**)ctx = dm->ctx;
2396   PetscFunctionReturn(0);
2397 }
2398 
2399 #undef __FUNCT__
2400 #define __FUNCT__ "DMSetVariableBounds"
2401 /*@C
2402     DMSetVariableBounds - sets a function to compute the lower and upper bound vectors for SNESVI.
2403 
2404     Logically Collective on DM
2405 
2406     Input Parameter:
2407 +   dm - the DM object
2408 -   f - the function that computes variable bounds used by SNESVI (use NULL to cancel a previous function that was set)
2409 
2410     Level: intermediate
2411 
2412 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext(),
2413          DMSetJacobian()
2414 
2415 @*/
2416 PetscErrorCode  DMSetVariableBounds(DM dm,PetscErrorCode (*f)(DM,Vec,Vec))
2417 {
2418   PetscFunctionBegin;
2419   dm->ops->computevariablebounds = f;
2420   PetscFunctionReturn(0);
2421 }
2422 
2423 #undef __FUNCT__
2424 #define __FUNCT__ "DMHasVariableBounds"
2425 /*@
2426     DMHasVariableBounds - does the DM object have a variable bounds function?
2427 
2428     Not Collective
2429 
2430     Input Parameter:
2431 .   dm - the DM object to destroy
2432 
2433     Output Parameter:
2434 .   flg - PETSC_TRUE if the variable bounds function exists
2435 
2436     Level: developer
2437 
2438 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2439 
2440 @*/
2441 PetscErrorCode  DMHasVariableBounds(DM dm,PetscBool  *flg)
2442 {
2443   PetscFunctionBegin;
2444   *flg =  (dm->ops->computevariablebounds) ? PETSC_TRUE : PETSC_FALSE;
2445   PetscFunctionReturn(0);
2446 }
2447 
2448 #undef __FUNCT__
2449 #define __FUNCT__ "DMComputeVariableBounds"
2450 /*@C
2451     DMComputeVariableBounds - compute variable bounds used by SNESVI.
2452 
2453     Logically Collective on DM
2454 
2455     Input Parameters:
2456 +   dm - the DM object to destroy
2457 -   x  - current solution at which the bounds are computed
2458 
2459     Output parameters:
2460 +   xl - lower bound
2461 -   xu - upper bound
2462 
2463     Level: intermediate
2464 
2465 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2466 
2467 @*/
2468 PetscErrorCode  DMComputeVariableBounds(DM dm, Vec xl, Vec xu)
2469 {
2470   PetscErrorCode ierr;
2471 
2472   PetscFunctionBegin;
2473   PetscValidHeaderSpecific(xl,VEC_CLASSID,2);
2474   PetscValidHeaderSpecific(xu,VEC_CLASSID,2);
2475   if (dm->ops->computevariablebounds) {
2476     ierr = (*dm->ops->computevariablebounds)(dm, xl,xu);CHKERRQ(ierr);
2477   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "This DM is incapable of computing variable bounds.");
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMHasColoring"
2483 /*@
2484     DMHasColoring - does the DM object have a method of providing a coloring?
2485 
2486     Not Collective
2487 
2488     Input Parameter:
2489 .   dm - the DM object
2490 
2491     Output Parameter:
2492 .   flg - PETSC_TRUE if the DM has facilities for DMCreateColoring().
2493 
2494     Level: developer
2495 
2496 .seealso DMHasFunction(), DMCreateColoring()
2497 
2498 @*/
2499 PetscErrorCode  DMHasColoring(DM dm,PetscBool  *flg)
2500 {
2501   PetscFunctionBegin;
2502   *flg =  (dm->ops->getcoloring) ? PETSC_TRUE : PETSC_FALSE;
2503   PetscFunctionReturn(0);
2504 }
2505 
2506 #undef  __FUNCT__
2507 #define __FUNCT__ "DMSetVec"
2508 /*@C
2509     DMSetVec - set the vector at which to compute residual, Jacobian and VI bounds, if the problem is nonlinear.
2510 
2511     Collective on DM
2512 
2513     Input Parameter:
2514 +   dm - the DM object
2515 -   x - location to compute residual and Jacobian, if NULL is passed to those routines; will be NULL for linear problems.
2516 
2517     Level: developer
2518 
2519 .seealso DMView(), DMCreateGlobalVector(), DMCreateInterpolation(), DMCreateColoring(), DMCreateMatrix(), DMGetApplicationContext()
2520 
2521 @*/
2522 PetscErrorCode  DMSetVec(DM dm,Vec x)
2523 {
2524   PetscErrorCode ierr;
2525 
2526   PetscFunctionBegin;
2527   if (x) {
2528     if (!dm->x) {
2529       ierr = DMCreateGlobalVector(dm,&dm->x);CHKERRQ(ierr);
2530     }
2531     ierr = VecCopy(x,dm->x);CHKERRQ(ierr);
2532   } else if (dm->x) {
2533     ierr = VecDestroy(&dm->x);CHKERRQ(ierr);
2534   }
2535   PetscFunctionReturn(0);
2536 }
2537 
2538 PetscFunctionList DMList              = NULL;
2539 PetscBool         DMRegisterAllCalled = PETSC_FALSE;
2540 
2541 #undef __FUNCT__
2542 #define __FUNCT__ "DMSetType"
2543 /*@C
2544   DMSetType - Builds a DM, for a particular DM implementation.
2545 
2546   Collective on DM
2547 
2548   Input Parameters:
2549 + dm     - The DM object
2550 - method - The name of the DM type
2551 
2552   Options Database Key:
2553 . -dm_type <type> - Sets the DM type; use -help for a list of available types
2554 
2555   Notes:
2556   See "petsc/include/petscdm.h" for available DM types (for instance, DM1D, DM2D, or DM3D).
2557 
2558   Level: intermediate
2559 
2560 .keywords: DM, set, type
2561 .seealso: DMGetType(), DMCreate()
2562 @*/
2563 PetscErrorCode  DMSetType(DM dm, DMType method)
2564 {
2565   PetscErrorCode (*r)(DM);
2566   PetscBool      match;
2567   PetscErrorCode ierr;
2568 
2569   PetscFunctionBegin;
2570   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2571   ierr = PetscObjectTypeCompare((PetscObject) dm, method, &match);CHKERRQ(ierr);
2572   if (match) PetscFunctionReturn(0);
2573 
2574   if (!DMRegisterAllCalled) {ierr = DMRegisterAll();CHKERRQ(ierr);}
2575   ierr = PetscFunctionListFind(DMList,method,&r);CHKERRQ(ierr);
2576   if (!r) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown DM type: %s", method);
2577 
2578   if (dm->ops->destroy) {
2579     ierr             = (*dm->ops->destroy)(dm);CHKERRQ(ierr);
2580     dm->ops->destroy = NULL;
2581   }
2582   ierr = (*r)(dm);CHKERRQ(ierr);
2583   ierr = PetscObjectChangeTypeName((PetscObject)dm,method);CHKERRQ(ierr);
2584   PetscFunctionReturn(0);
2585 }
2586 
2587 #undef __FUNCT__
2588 #define __FUNCT__ "DMGetType"
2589 /*@C
2590   DMGetType - Gets the DM type name (as a string) from the DM.
2591 
2592   Not Collective
2593 
2594   Input Parameter:
2595 . dm  - The DM
2596 
2597   Output Parameter:
2598 . type - The DM type name
2599 
2600   Level: intermediate
2601 
2602 .keywords: DM, get, type, name
2603 .seealso: DMSetType(), DMCreate()
2604 @*/
2605 PetscErrorCode  DMGetType(DM dm, DMType *type)
2606 {
2607   PetscErrorCode ierr;
2608 
2609   PetscFunctionBegin;
2610   PetscValidHeaderSpecific(dm, DM_CLASSID,1);
2611   PetscValidPointer(type,2);
2612   if (!DMRegisterAllCalled) {
2613     ierr = DMRegisterAll();CHKERRQ(ierr);
2614   }
2615   *type = ((PetscObject)dm)->type_name;
2616   PetscFunctionReturn(0);
2617 }
2618 
2619 #undef __FUNCT__
2620 #define __FUNCT__ "DMConvert"
2621 /*@C
2622   DMConvert - Converts a DM to another DM, either of the same or different type.
2623 
2624   Collective on DM
2625 
2626   Input Parameters:
2627 + dm - the DM
2628 - newtype - new DM type (use "same" for the same type)
2629 
2630   Output Parameter:
2631 . M - pointer to new DM
2632 
2633   Notes:
2634   Cannot be used to convert a sequential DM to parallel or parallel to sequential,
2635   the MPI communicator of the generated DM is always the same as the communicator
2636   of the input DM.
2637 
2638   Level: intermediate
2639 
2640 .seealso: DMCreate()
2641 @*/
2642 PetscErrorCode DMConvert(DM dm, DMType newtype, DM *M)
2643 {
2644   DM             B;
2645   char           convname[256];
2646   PetscBool      sametype, issame;
2647   PetscErrorCode ierr;
2648 
2649   PetscFunctionBegin;
2650   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2651   PetscValidType(dm,1);
2652   PetscValidPointer(M,3);
2653   ierr = PetscObjectTypeCompare((PetscObject) dm, newtype, &sametype);CHKERRQ(ierr);
2654   ierr = PetscStrcmp(newtype, "same", &issame);CHKERRQ(ierr);
2655   {
2656     PetscErrorCode (*conv)(DM, DMType, DM*) = NULL;
2657 
2658     /*
2659        Order of precedence:
2660        1) See if a specialized converter is known to the current DM.
2661        2) See if a specialized converter is known to the desired DM class.
2662        3) See if a good general converter is registered for the desired class
2663        4) See if a good general converter is known for the current matrix.
2664        5) Use a really basic converter.
2665     */
2666 
2667     /* 1) See if a specialized converter is known to the current DM and the desired class */
2668     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2669     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2670     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2671     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2672     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2673     ierr = PetscObjectQueryFunction((PetscObject)dm,convname,&conv);CHKERRQ(ierr);
2674     if (conv) goto foundconv;
2675 
2676     /* 2)  See if a specialized converter is known to the desired DM class. */
2677     ierr = DMCreate(PetscObjectComm((PetscObject)dm), &B);CHKERRQ(ierr);
2678     ierr = DMSetType(B, newtype);CHKERRQ(ierr);
2679     ierr = PetscStrcpy(convname,"DMConvert_");CHKERRQ(ierr);
2680     ierr = PetscStrcat(convname,((PetscObject) dm)->type_name);CHKERRQ(ierr);
2681     ierr = PetscStrcat(convname,"_");CHKERRQ(ierr);
2682     ierr = PetscStrcat(convname,newtype);CHKERRQ(ierr);
2683     ierr = PetscStrcat(convname,"_C");CHKERRQ(ierr);
2684     ierr = PetscObjectQueryFunction((PetscObject)B,convname,&conv);CHKERRQ(ierr);
2685     if (conv) {
2686       ierr = DMDestroy(&B);CHKERRQ(ierr);
2687       goto foundconv;
2688     }
2689 
2690 #if 0
2691     /* 3) See if a good general converter is registered for the desired class */
2692     conv = B->ops->convertfrom;
2693     ierr = DMDestroy(&B);CHKERRQ(ierr);
2694     if (conv) goto foundconv;
2695 
2696     /* 4) See if a good general converter is known for the current matrix */
2697     if (dm->ops->convert) {
2698       conv = dm->ops->convert;
2699     }
2700     if (conv) goto foundconv;
2701 #endif
2702 
2703     /* 5) Use a really basic converter. */
2704     SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No conversion possible between DM types %s and %s", ((PetscObject) dm)->type_name, newtype);
2705 
2706 foundconv:
2707     ierr = PetscLogEventBegin(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2708     ierr = (*conv)(dm,newtype,M);CHKERRQ(ierr);
2709     ierr = PetscLogEventEnd(DM_Convert,dm,0,0,0);CHKERRQ(ierr);
2710   }
2711   ierr = PetscObjectStateIncrease((PetscObject) *M);CHKERRQ(ierr);
2712   PetscFunctionReturn(0);
2713 }
2714 
2715 /*--------------------------------------------------------------------------------------------------------------------*/
2716 
2717 #undef __FUNCT__
2718 #define __FUNCT__ "DMRegister"
2719 /*@C
2720   DMRegister -  Adds a new DM component implementation
2721 
2722   Not Collective
2723 
2724   Input Parameters:
2725 + name        - The name of a new user-defined creation routine
2726 - create_func - The creation routine itself
2727 
2728   Notes:
2729   DMRegister() may be called multiple times to add several user-defined DMs
2730 
2731 
2732   Sample usage:
2733 .vb
2734     DMRegister("my_da", MyDMCreate);
2735 .ve
2736 
2737   Then, your DM type can be chosen with the procedural interface via
2738 .vb
2739     DMCreate(MPI_Comm, DM *);
2740     DMSetType(DM,"my_da");
2741 .ve
2742    or at runtime via the option
2743 .vb
2744     -da_type my_da
2745 .ve
2746 
2747   Level: advanced
2748 
2749 .keywords: DM, register
2750 .seealso: DMRegisterAll(), DMRegisterDestroy()
2751 
2752 @*/
2753 PetscErrorCode  DMRegister(const char sname[],PetscErrorCode (*function)(DM))
2754 {
2755   PetscErrorCode ierr;
2756 
2757   PetscFunctionBegin;
2758   ierr = PetscFunctionListAdd(&DMList,sname,function);CHKERRQ(ierr);
2759   PetscFunctionReturn(0);
2760 }
2761 
2762 #undef __FUNCT__
2763 #define __FUNCT__ "DMLoad"
2764 /*@C
2765   DMLoad - Loads a DM that has been stored in binary  with DMView().
2766 
2767   Collective on PetscViewer
2768 
2769   Input Parameters:
2770 + newdm - the newly loaded DM, this needs to have been created with DMCreate() or
2771            some related function before a call to DMLoad().
2772 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
2773            HDF5 file viewer, obtained from PetscViewerHDF5Open()
2774 
2775    Level: intermediate
2776 
2777   Notes:
2778    The type is determined by the data in the file, any type set into the DM before this call is ignored.
2779 
2780   Notes for advanced users:
2781   Most users should not need to know the details of the binary storage
2782   format, since DMLoad() and DMView() completely hide these details.
2783   But for anyone who's interested, the standard binary matrix storage
2784   format is
2785 .vb
2786      has not yet been determined
2787 .ve
2788 
2789 .seealso: PetscViewerBinaryOpen(), DMView(), MatLoad(), VecLoad()
2790 @*/
2791 PetscErrorCode  DMLoad(DM newdm, PetscViewer viewer)
2792 {
2793   PetscBool      isbinary, ishdf5;
2794   PetscErrorCode ierr;
2795 
2796   PetscFunctionBegin;
2797   PetscValidHeaderSpecific(newdm,DM_CLASSID,1);
2798   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
2799   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
2800   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5);CHKERRQ(ierr);
2801   if (isbinary) {
2802     PetscInt classid;
2803     char     type[256];
2804 
2805     ierr = PetscViewerBinaryRead(viewer,&classid,1,PETSC_INT);CHKERRQ(ierr);
2806     if (classid != DM_FILE_CLASSID) SETERRQ1(PetscObjectComm((PetscObject)newdm),PETSC_ERR_ARG_WRONG,"Not DM next in file, classid found %d",(int)classid);
2807     ierr = PetscViewerBinaryRead(viewer,type,256,PETSC_CHAR);CHKERRQ(ierr);
2808     ierr = DMSetType(newdm, type);CHKERRQ(ierr);
2809     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
2810   } else if (ishdf5) {
2811     if (newdm->ops->load) {ierr = (*newdm->ops->load)(newdm,viewer);CHKERRQ(ierr);}
2812   } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen() or PetscViewerHDF5Open()");
2813   PetscFunctionReturn(0);
2814 }
2815 
2816 /******************************** FEM Support **********************************/
2817 
2818 #undef __FUNCT__
2819 #define __FUNCT__ "DMPrintCellVector"
2820 PetscErrorCode DMPrintCellVector(PetscInt c, const char name[], PetscInt len, const PetscScalar x[])
2821 {
2822   PetscInt       f;
2823   PetscErrorCode ierr;
2824 
2825   PetscFunctionBegin;
2826   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
2827   for (f = 0; f < len; ++f) {
2828     ierr = PetscPrintf(PETSC_COMM_SELF, "  | %g |\n", (double)PetscRealPart(x[f]));CHKERRQ(ierr);
2829   }
2830   PetscFunctionReturn(0);
2831 }
2832 
2833 #undef __FUNCT__
2834 #define __FUNCT__ "DMPrintCellMatrix"
2835 PetscErrorCode DMPrintCellMatrix(PetscInt c, const char name[], PetscInt rows, PetscInt cols, const PetscScalar A[])
2836 {
2837   PetscInt       f, g;
2838   PetscErrorCode ierr;
2839 
2840   PetscFunctionBegin;
2841   ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D Element %s\n", c, name);CHKERRQ(ierr);
2842   for (f = 0; f < rows; ++f) {
2843     ierr = PetscPrintf(PETSC_COMM_SELF, "  |");CHKERRQ(ierr);
2844     for (g = 0; g < cols; ++g) {
2845       ierr = PetscPrintf(PETSC_COMM_SELF, " % 9.5g", PetscRealPart(A[f*cols+g]));CHKERRQ(ierr);
2846     }
2847     ierr = PetscPrintf(PETSC_COMM_SELF, " |\n");CHKERRQ(ierr);
2848   }
2849   PetscFunctionReturn(0);
2850 }
2851 
2852 #undef __FUNCT__
2853 #define __FUNCT__ "DMPrintLocalVec"
2854 PetscErrorCode DMPrintLocalVec(DM dm, const char name[], PetscReal tol, Vec X)
2855 {
2856   PetscMPIInt    rank, numProcs;
2857   PetscInt       p;
2858   PetscErrorCode ierr;
2859 
2860   PetscFunctionBegin;
2861   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
2862   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
2863   ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "%s:\n", name);CHKERRQ(ierr);
2864   for (p = 0; p < numProcs; ++p) {
2865     if (p == rank) {
2866       Vec x;
2867 
2868       ierr = VecDuplicate(X, &x);CHKERRQ(ierr);
2869       ierr = VecCopy(X, x);CHKERRQ(ierr);
2870       ierr = VecChop(x, tol);CHKERRQ(ierr);
2871       ierr = VecView(x, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
2872       ierr = VecDestroy(&x);CHKERRQ(ierr);
2873       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
2874     }
2875     ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
2876   }
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 #undef __FUNCT__
2881 #define __FUNCT__ "DMGetDefaultSection"
2882 /*@
2883   DMGetDefaultSection - Get the PetscSection encoding the local data layout for the DM.
2884 
2885   Input Parameter:
2886 . dm - The DM
2887 
2888   Output Parameter:
2889 . section - The PetscSection
2890 
2891   Level: intermediate
2892 
2893   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
2894 
2895 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
2896 @*/
2897 PetscErrorCode DMGetDefaultSection(DM dm, PetscSection *section)
2898 {
2899   PetscErrorCode ierr;
2900 
2901   PetscFunctionBegin;
2902   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2903   PetscValidPointer(section, 2);
2904   if (!dm->defaultSection && dm->ops->createdefaultsection) {ierr = (*dm->ops->createdefaultsection)(dm);CHKERRQ(ierr);}
2905   *section = dm->defaultSection;
2906   PetscFunctionReturn(0);
2907 }
2908 
2909 #undef __FUNCT__
2910 #define __FUNCT__ "DMSetDefaultSection"
2911 /*@
2912   DMSetDefaultSection - Set the PetscSection encoding the local data layout for the DM.
2913 
2914   Input Parameters:
2915 + dm - The DM
2916 - section - The PetscSection
2917 
2918   Level: intermediate
2919 
2920   Note: Any existing Section will be destroyed
2921 
2922 .seealso: DMSetDefaultSection(), DMGetDefaultGlobalSection()
2923 @*/
2924 PetscErrorCode DMSetDefaultSection(DM dm, PetscSection section)
2925 {
2926   PetscInt       numFields;
2927   PetscInt       f;
2928   PetscErrorCode ierr;
2929 
2930   PetscFunctionBegin;
2931   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2932   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
2933   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
2934   ierr = PetscSectionDestroy(&dm->defaultSection);CHKERRQ(ierr);
2935   dm->defaultSection = section;
2936   ierr = PetscSectionGetNumFields(dm->defaultSection, &numFields);CHKERRQ(ierr);
2937   if (numFields) {
2938     ierr = DMSetNumFields(dm, numFields);CHKERRQ(ierr);
2939     for (f = 0; f < numFields; ++f) {
2940       PetscObject disc;
2941       const char *name;
2942 
2943       ierr = PetscSectionGetFieldName(dm->defaultSection, f, &name);CHKERRQ(ierr);
2944       ierr = DMGetField(dm, f, &disc);CHKERRQ(ierr);
2945       ierr = PetscObjectSetName(disc, name);CHKERRQ(ierr);
2946     }
2947   }
2948   /* The global section will be rebuilt in the next call to DMGetDefaultGlobalSection(). */
2949   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
2950   PetscFunctionReturn(0);
2951 }
2952 
2953 #undef __FUNCT__
2954 #define __FUNCT__ "DMGetDefaultGlobalSection"
2955 /*@
2956   DMGetDefaultGlobalSection - Get the PetscSection encoding the global data layout for the DM.
2957 
2958   Collective on DM
2959 
2960   Input Parameter:
2961 . dm - The DM
2962 
2963   Output Parameter:
2964 . section - The PetscSection
2965 
2966   Level: intermediate
2967 
2968   Note: This gets a borrowed reference, so the user should not destroy this PetscSection.
2969 
2970 .seealso: DMSetDefaultSection(), DMGetDefaultSection()
2971 @*/
2972 PetscErrorCode DMGetDefaultGlobalSection(DM dm, PetscSection *section)
2973 {
2974   PetscErrorCode ierr;
2975 
2976   PetscFunctionBegin;
2977   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2978   PetscValidPointer(section, 2);
2979   if (!dm->defaultGlobalSection) {
2980     PetscSection s;
2981 
2982     ierr = DMGetDefaultSection(dm, &s);CHKERRQ(ierr);
2983     if (!s)  SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection");
2984     if (!dm->sf) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSF in order to create a global PetscSection");
2985     ierr = PetscSectionCreateGlobalSection(s, dm->sf, PETSC_FALSE, &dm->defaultGlobalSection);CHKERRQ(ierr);
2986     ierr = PetscLayoutDestroy(&dm->map);CHKERRQ(ierr);
2987     ierr = PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->defaultGlobalSection, &dm->map);CHKERRQ(ierr);
2988   }
2989   *section = dm->defaultGlobalSection;
2990   PetscFunctionReturn(0);
2991 }
2992 
2993 #undef __FUNCT__
2994 #define __FUNCT__ "DMSetDefaultGlobalSection"
2995 /*@
2996   DMSetDefaultGlobalSection - Set the PetscSection encoding the global data layout for the DM.
2997 
2998   Input Parameters:
2999 + dm - The DM
3000 - section - The PetscSection, or NULL
3001 
3002   Level: intermediate
3003 
3004   Note: Any existing Section will be destroyed
3005 
3006 .seealso: DMGetDefaultGlobalSection(), DMSetDefaultSection()
3007 @*/
3008 PetscErrorCode DMSetDefaultGlobalSection(DM dm, PetscSection section)
3009 {
3010   PetscErrorCode ierr;
3011 
3012   PetscFunctionBegin;
3013   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3014   if (section) PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
3015   ierr = PetscObjectReference((PetscObject)section);CHKERRQ(ierr);
3016   ierr = PetscSectionDestroy(&dm->defaultGlobalSection);CHKERRQ(ierr);
3017   dm->defaultGlobalSection = section;
3018   PetscFunctionReturn(0);
3019 }
3020 
3021 #undef __FUNCT__
3022 #define __FUNCT__ "DMGetDefaultSF"
3023 /*@
3024   DMGetDefaultSF - Get the PetscSF encoding the parallel dof overlap for the DM. If it has not been set,
3025   it is created from the default PetscSection layouts in the DM.
3026 
3027   Input Parameter:
3028 . dm - The DM
3029 
3030   Output Parameter:
3031 . sf - The PetscSF
3032 
3033   Level: intermediate
3034 
3035   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3036 
3037 .seealso: DMSetDefaultSF(), DMCreateDefaultSF()
3038 @*/
3039 PetscErrorCode DMGetDefaultSF(DM dm, PetscSF *sf)
3040 {
3041   PetscInt       nroots;
3042   PetscErrorCode ierr;
3043 
3044   PetscFunctionBegin;
3045   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3046   PetscValidPointer(sf, 2);
3047   ierr = PetscSFGetGraph(dm->defaultSF, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
3048   if (nroots < 0) {
3049     PetscSection section, gSection;
3050 
3051     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
3052     if (section) {
3053       ierr = DMGetDefaultGlobalSection(dm, &gSection);CHKERRQ(ierr);
3054       ierr = DMCreateDefaultSF(dm, section, gSection);CHKERRQ(ierr);
3055     } else {
3056       *sf = NULL;
3057       PetscFunctionReturn(0);
3058     }
3059   }
3060   *sf = dm->defaultSF;
3061   PetscFunctionReturn(0);
3062 }
3063 
3064 #undef __FUNCT__
3065 #define __FUNCT__ "DMSetDefaultSF"
3066 /*@
3067   DMSetDefaultSF - Set the PetscSF encoding the parallel dof overlap for the DM
3068 
3069   Input Parameters:
3070 + dm - The DM
3071 - sf - The PetscSF
3072 
3073   Level: intermediate
3074 
3075   Note: Any previous SF is destroyed
3076 
3077 .seealso: DMGetDefaultSF(), DMCreateDefaultSF()
3078 @*/
3079 PetscErrorCode DMSetDefaultSF(DM dm, PetscSF sf)
3080 {
3081   PetscErrorCode ierr;
3082 
3083   PetscFunctionBegin;
3084   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3085   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2);
3086   ierr          = PetscSFDestroy(&dm->defaultSF);CHKERRQ(ierr);
3087   dm->defaultSF = sf;
3088   PetscFunctionReturn(0);
3089 }
3090 
3091 #undef __FUNCT__
3092 #define __FUNCT__ "DMCreateDefaultSF"
3093 /*@C
3094   DMCreateDefaultSF - Create the PetscSF encoding the parallel dof overlap for the DM based upon the PetscSections
3095   describing the data layout.
3096 
3097   Input Parameters:
3098 + dm - The DM
3099 . localSection - PetscSection describing the local data layout
3100 - globalSection - PetscSection describing the global data layout
3101 
3102   Level: intermediate
3103 
3104 .seealso: DMGetDefaultSF(), DMSetDefaultSF()
3105 @*/
3106 PetscErrorCode DMCreateDefaultSF(DM dm, PetscSection localSection, PetscSection globalSection)
3107 {
3108   MPI_Comm       comm;
3109   PetscLayout    layout;
3110   const PetscInt *ranges;
3111   PetscInt       *local;
3112   PetscSFNode    *remote;
3113   PetscInt       pStart, pEnd, p, nroots, nleaves = 0, l;
3114   PetscMPIInt    size, rank;
3115   PetscErrorCode ierr;
3116 
3117   PetscFunctionBegin;
3118   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3119   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3120   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
3121   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3122   ierr = PetscSectionGetChart(globalSection, &pStart, &pEnd);CHKERRQ(ierr);
3123   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &nroots);CHKERRQ(ierr);
3124   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
3125   ierr = PetscLayoutSetBlockSize(layout, 1);CHKERRQ(ierr);
3126   ierr = PetscLayoutSetLocalSize(layout, nroots);CHKERRQ(ierr);
3127   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
3128   ierr = PetscLayoutGetRanges(layout, &ranges);CHKERRQ(ierr);
3129   for (p = pStart; p < pEnd; ++p) {
3130     PetscInt gdof, gcdof;
3131 
3132     ierr     = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3133     ierr     = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3134     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));
3135     nleaves += gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3136   }
3137   ierr = PetscMalloc1(nleaves, &local);CHKERRQ(ierr);
3138   ierr = PetscMalloc1(nleaves, &remote);CHKERRQ(ierr);
3139   for (p = pStart, l = 0; p < pEnd; ++p) {
3140     const PetscInt *cind;
3141     PetscInt       dof, cdof, off, gdof, gcdof, goff, gsize, d, c;
3142 
3143     ierr = PetscSectionGetDof(localSection, p, &dof);CHKERRQ(ierr);
3144     ierr = PetscSectionGetOffset(localSection, p, &off);CHKERRQ(ierr);
3145     ierr = PetscSectionGetConstraintDof(localSection, p, &cdof);CHKERRQ(ierr);
3146     ierr = PetscSectionGetConstraintIndices(localSection, p, &cind);CHKERRQ(ierr);
3147     ierr = PetscSectionGetDof(globalSection, p, &gdof);CHKERRQ(ierr);
3148     ierr = PetscSectionGetConstraintDof(globalSection, p, &gcdof);CHKERRQ(ierr);
3149     ierr = PetscSectionGetOffset(globalSection, p, &goff);CHKERRQ(ierr);
3150     if (!gdof) continue; /* Censored point */
3151     gsize = gdof < 0 ? -(gdof+1)-gcdof : gdof-gcdof;
3152     if (gsize != dof-cdof) {
3153       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);
3154       cdof = 0; /* Ignore constraints */
3155     }
3156     for (d = 0, c = 0; d < dof; ++d) {
3157       if ((c < cdof) && (cind[c] == d)) {++c; continue;}
3158       local[l+d-c] = off+d;
3159     }
3160     if (gdof < 0) {
3161       for (d = 0; d < gsize; ++d, ++l) {
3162         PetscInt offset = -(goff+1) + d, r;
3163 
3164         ierr = PetscFindInt(offset,size+1,ranges,&r);CHKERRQ(ierr);
3165         if (r < 0) r = -(r+2);
3166         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);
3167         remote[l].rank  = r;
3168         remote[l].index = offset - ranges[r];
3169       }
3170     } else {
3171       for (d = 0; d < gsize; ++d, ++l) {
3172         remote[l].rank  = rank;
3173         remote[l].index = goff+d - ranges[rank];
3174       }
3175     }
3176   }
3177   if (l != nleaves) SETERRQ2(comm, PETSC_ERR_PLIB, "Iteration error, l %d != nleaves %d", l, nleaves);
3178   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3179   ierr = PetscSFSetGraph(dm->defaultSF, nroots, nleaves, local, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
3180   PetscFunctionReturn(0);
3181 }
3182 
3183 #undef __FUNCT__
3184 #define __FUNCT__ "DMGetPointSF"
3185 /*@
3186   DMGetPointSF - Get the PetscSF encoding the parallel section point overlap for the DM.
3187 
3188   Input Parameter:
3189 . dm - The DM
3190 
3191   Output Parameter:
3192 . sf - The PetscSF
3193 
3194   Level: intermediate
3195 
3196   Note: This gets a borrowed reference, so the user should not destroy this PetscSF.
3197 
3198 .seealso: DMSetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3199 @*/
3200 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf)
3201 {
3202   PetscFunctionBegin;
3203   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3204   PetscValidPointer(sf, 2);
3205   *sf = dm->sf;
3206   PetscFunctionReturn(0);
3207 }
3208 
3209 #undef __FUNCT__
3210 #define __FUNCT__ "DMSetPointSF"
3211 /*@
3212   DMSetPointSF - Set the PetscSF encoding the parallel section point overlap for the DM.
3213 
3214   Input Parameters:
3215 + dm - The DM
3216 - sf - The PetscSF
3217 
3218   Level: intermediate
3219 
3220 .seealso: DMGetPointSF(), DMGetDefaultSF(), DMSetDefaultSF(), DMCreateDefaultSF()
3221 @*/
3222 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf)
3223 {
3224   PetscErrorCode ierr;
3225 
3226   PetscFunctionBegin;
3227   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3228   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3229   ierr   = PetscSFDestroy(&dm->sf);CHKERRQ(ierr);
3230   ierr   = PetscObjectReference((PetscObject) sf);CHKERRQ(ierr);
3231   dm->sf = sf;
3232   PetscFunctionReturn(0);
3233 }
3234 
3235 #undef __FUNCT__
3236 #define __FUNCT__ "DMGetDS"
3237 /*@
3238   DMGetDS - Get the PetscDS
3239 
3240   Input Parameter:
3241 . dm - The DM
3242 
3243   Output Parameter:
3244 . prob - The PetscDS
3245 
3246   Level: developer
3247 
3248 .seealso: DMSetDS()
3249 @*/
3250 PetscErrorCode DMGetDS(DM dm, PetscDS *prob)
3251 {
3252   PetscFunctionBegin;
3253   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3254   PetscValidPointer(prob, 2);
3255   *prob = dm->prob;
3256   PetscFunctionReturn(0);
3257 }
3258 
3259 #undef __FUNCT__
3260 #define __FUNCT__ "DMSetDS"
3261 /*@
3262   DMSetDS - Set the PetscDS
3263 
3264   Input Parameters:
3265 + dm - The DM
3266 - prob - The PetscDS
3267 
3268   Level: developer
3269 
3270 .seealso: DMGetDS()
3271 @*/
3272 PetscErrorCode DMSetDS(DM dm, PetscDS prob)
3273 {
3274   PetscErrorCode ierr;
3275 
3276   PetscFunctionBegin;
3277   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3278   PetscValidHeaderSpecific(prob, PETSCDS_CLASSID, 2);
3279   ierr = PetscDSDestroy(&dm->prob);CHKERRQ(ierr);
3280   dm->prob = prob;
3281   ierr = PetscObjectReference((PetscObject) dm->prob);CHKERRQ(ierr);
3282   PetscFunctionReturn(0);
3283 }
3284 
3285 #undef __FUNCT__
3286 #define __FUNCT__ "DMGetNumFields"
3287 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields)
3288 {
3289   PetscErrorCode ierr;
3290 
3291   PetscFunctionBegin;
3292   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3293   ierr = PetscDSGetNumFields(dm->prob, numFields);CHKERRQ(ierr);
3294   PetscFunctionReturn(0);
3295 }
3296 
3297 #undef __FUNCT__
3298 #define __FUNCT__ "DMSetNumFields"
3299 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields)
3300 {
3301   PetscInt       Nf, f;
3302   PetscErrorCode ierr;
3303 
3304   PetscFunctionBegin;
3305   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3306   ierr = PetscDSGetNumFields(dm->prob, &Nf);CHKERRQ(ierr);
3307   for (f = Nf; f < numFields; ++f) {
3308     PetscContainer obj;
3309 
3310     ierr = PetscContainerCreate(PetscObjectComm((PetscObject) dm), &obj);CHKERRQ(ierr);
3311     ierr = PetscDSSetDiscretization(dm->prob, f, (PetscObject) obj);CHKERRQ(ierr);
3312     ierr = PetscContainerDestroy(&obj);CHKERRQ(ierr);
3313   }
3314   PetscFunctionReturn(0);
3315 }
3316 
3317 #undef __FUNCT__
3318 #define __FUNCT__ "DMGetField"
3319 /*@
3320   DMGetField - Return the discretization object for a given DM field
3321 
3322   Not collective
3323 
3324   Input Parameters:
3325 + dm - The DM
3326 - f  - The field number
3327 
3328   Output Parameter:
3329 . field - The discretization object
3330 
3331   Level: developer
3332 
3333 .seealso: DMSetField()
3334 @*/
3335 PetscErrorCode DMGetField(DM dm, PetscInt f, PetscObject *field)
3336 {
3337   PetscErrorCode ierr;
3338 
3339   PetscFunctionBegin;
3340   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3341   ierr = PetscDSGetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3342   PetscFunctionReturn(0);
3343 }
3344 
3345 #undef __FUNCT__
3346 #define __FUNCT__ "DMSetField"
3347 /*@
3348   DMSetField - Set the discretization object for a given DM field
3349 
3350   Logically collective on DM
3351 
3352   Input Parameters:
3353 + dm - The DM
3354 . f  - The field number
3355 - field - The discretization object
3356 
3357   Level: developer
3358 
3359 .seealso: DMGetField()
3360 @*/
3361 PetscErrorCode DMSetField(DM dm, PetscInt f, PetscObject field)
3362 {
3363   PetscErrorCode ierr;
3364 
3365   PetscFunctionBegin;
3366   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3367   ierr = PetscDSSetDiscretization(dm->prob, f, field);CHKERRQ(ierr);
3368   PetscFunctionReturn(0);
3369 }
3370 
3371 #undef __FUNCT__
3372 #define __FUNCT__ "DMRestrictHook_Coordinates"
3373 PetscErrorCode DMRestrictHook_Coordinates(DM dm,DM dmc,void *ctx)
3374 {
3375   DM dm_coord,dmc_coord;
3376   PetscErrorCode ierr;
3377   Vec coords,ccoords;
3378   VecScatter scat;
3379   PetscFunctionBegin;
3380   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3381   ierr = DMGetCoordinateDM(dmc,&dmc_coord);CHKERRQ(ierr);
3382   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3383   ierr = DMGetCoordinates(dmc,&ccoords);CHKERRQ(ierr);
3384   if (coords && !ccoords) {
3385     ierr = DMCreateGlobalVector(dmc_coord,&ccoords);CHKERRQ(ierr);
3386     ierr = DMCreateInjection(dmc_coord,dm_coord,&scat);CHKERRQ(ierr);
3387     ierr = VecScatterBegin(scat,coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3388     ierr = VecScatterEnd(scat,coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3389     ierr = DMSetCoordinates(dmc,ccoords);CHKERRQ(ierr);
3390     ierr = VecScatterDestroy(&scat);CHKERRQ(ierr);
3391     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3392   }
3393   PetscFunctionReturn(0);
3394 }
3395 
3396 #undef __FUNCT__
3397 #define __FUNCT__ "DMSubDomainHook_Coordinates"
3398 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm,DM subdm,void *ctx)
3399 {
3400   DM dm_coord,subdm_coord;
3401   PetscErrorCode ierr;
3402   Vec coords,ccoords,clcoords;
3403   VecScatter *scat_i,*scat_g;
3404   PetscFunctionBegin;
3405   ierr = DMGetCoordinateDM(dm,&dm_coord);CHKERRQ(ierr);
3406   ierr = DMGetCoordinateDM(subdm,&subdm_coord);CHKERRQ(ierr);
3407   ierr = DMGetCoordinates(dm,&coords);CHKERRQ(ierr);
3408   ierr = DMGetCoordinates(subdm,&ccoords);CHKERRQ(ierr);
3409   if (coords && !ccoords) {
3410     ierr = DMCreateGlobalVector(subdm_coord,&ccoords);CHKERRQ(ierr);
3411     ierr = DMCreateLocalVector(subdm_coord,&clcoords);CHKERRQ(ierr);
3412     ierr = DMCreateDomainDecompositionScatters(dm_coord,1,&subdm_coord,NULL,&scat_i,&scat_g);CHKERRQ(ierr);
3413     ierr = VecScatterBegin(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3414     ierr = VecScatterBegin(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3415     ierr = VecScatterEnd(scat_i[0],coords,ccoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3416     ierr = VecScatterEnd(scat_g[0],coords,clcoords,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
3417     ierr = DMSetCoordinates(subdm,ccoords);CHKERRQ(ierr);
3418     ierr = DMSetCoordinatesLocal(subdm,clcoords);CHKERRQ(ierr);
3419     ierr = VecScatterDestroy(&scat_i[0]);CHKERRQ(ierr);
3420     ierr = VecScatterDestroy(&scat_g[0]);CHKERRQ(ierr);
3421     ierr = VecDestroy(&ccoords);CHKERRQ(ierr);
3422     ierr = VecDestroy(&clcoords);CHKERRQ(ierr);
3423     ierr = PetscFree(scat_i);CHKERRQ(ierr);
3424     ierr = PetscFree(scat_g);CHKERRQ(ierr);
3425   }
3426   PetscFunctionReturn(0);
3427 }
3428 
3429 #undef __FUNCT__
3430 #define __FUNCT__ "DMGetDimension"
3431 /*@
3432   DMGetDimension - Return the topological dimension of the DM
3433 
3434   Not collective
3435 
3436   Input Parameter:
3437 . dm - The DM
3438 
3439   Output Parameter:
3440 . dim - The topological dimension
3441 
3442   Level: beginner
3443 
3444 .seealso: DMSetDimension(), DMCreate()
3445 @*/
3446 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim)
3447 {
3448   PetscFunctionBegin;
3449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3450   PetscValidPointer(dim, 2);
3451   *dim = dm->dim;
3452   PetscFunctionReturn(0);
3453 }
3454 
3455 #undef __FUNCT__
3456 #define __FUNCT__ "DMSetDimension"
3457 /*@
3458   DMSetDimension - Set the topological dimension of the DM
3459 
3460   Collective on dm
3461 
3462   Input Parameters:
3463 + dm - The DM
3464 - dim - The topological dimension
3465 
3466   Level: beginner
3467 
3468 .seealso: DMGetDimension(), DMCreate()
3469 @*/
3470 PetscErrorCode DMSetDimension(DM dm, PetscInt dim)
3471 {
3472   PetscFunctionBegin;
3473   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3474   PetscValidLogicalCollectiveInt(dm, dim, 2);
3475   dm->dim = dim;
3476   PetscFunctionReturn(0);
3477 }
3478 
3479 #undef __FUNCT__
3480 #define __FUNCT__ "DMGetDimPoints"
3481 /*@
3482   DMGetDimPoints - Get the half-open interval for all points of a given dimension
3483 
3484   Collective on DM
3485 
3486   Input Parameters:
3487 + dm - the DM
3488 - dim - the dimension
3489 
3490   Output Parameters:
3491 + pStart - The first point of the given dimension
3492 . pEnd - The first point following points of the given dimension
3493 
3494   Note:
3495   The points are vertices in the Hasse diagram encoding the topology. This is explained in
3496   http://arxiv.org/abs/0908.4427. If not points exist of this dimension in the storage scheme,
3497   then the interval is empty.
3498 
3499   Level: intermediate
3500 
3501 .keywords: point, Hasse Diagram, dimension
3502 .seealso: DMPLEX, DMPlexGetDepthStratum(), DMPlexGetHeightStratum()
3503 @*/
3504 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd)
3505 {
3506   PetscInt       d;
3507   PetscErrorCode ierr;
3508 
3509   PetscFunctionBegin;
3510   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3511   ierr = DMGetDimension(dm, &d);CHKERRQ(ierr);
3512   if ((dim < 0) || (dim > d)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d 1", dim, d);
3513   ierr = (*dm->ops->getdimpoints)(dm, dim, pStart, pEnd);CHKERRQ(ierr);
3514   PetscFunctionReturn(0);
3515 }
3516 
3517 #undef __FUNCT__
3518 #define __FUNCT__ "DMSetCoordinates"
3519 /*@
3520   DMSetCoordinates - Sets into the DM a global vector that holds the coordinates
3521 
3522   Collective on DM
3523 
3524   Input Parameters:
3525 + dm - the DM
3526 - c - coordinate vector
3527 
3528   Note:
3529   The coordinates do include those for ghost points, which are in the local vector
3530 
3531   Level: intermediate
3532 
3533 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3534 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLoca(), DMGetCoordinateDM()
3535 @*/
3536 PetscErrorCode DMSetCoordinates(DM dm, Vec c)
3537 {
3538   PetscErrorCode ierr;
3539 
3540   PetscFunctionBegin;
3541   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3542   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3543   ierr            = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3544   ierr            = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3545   dm->coordinates = c;
3546   ierr            = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3547   ierr            = DMCoarsenHookAdd(dm,DMRestrictHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3548   ierr            = DMSubDomainHookAdd(dm,DMSubDomainHook_Coordinates,NULL,NULL);CHKERRQ(ierr);
3549   PetscFunctionReturn(0);
3550 }
3551 
3552 #undef __FUNCT__
3553 #define __FUNCT__ "DMSetCoordinatesLocal"
3554 /*@
3555   DMSetCoordinatesLocal - Sets into the DM a local vector that holds the coordinates
3556 
3557   Collective on DM
3558 
3559    Input Parameters:
3560 +  dm - the DM
3561 -  c - coordinate vector
3562 
3563   Note:
3564   The coordinates of ghost points can be set using DMSetCoordinates()
3565   followed by DMGetCoordinatesLocal(). This is intended to enable the
3566   setting of ghost coordinates outside of the domain.
3567 
3568   Level: intermediate
3569 
3570 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3571 .seealso: DMGetCoordinatesLocal(), DMSetCoordinates(), DMGetCoordinates(), DMGetCoordinateDM()
3572 @*/
3573 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c)
3574 {
3575   PetscErrorCode ierr;
3576 
3577   PetscFunctionBegin;
3578   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3579   PetscValidHeaderSpecific(c,VEC_CLASSID,2);
3580   ierr = PetscObjectReference((PetscObject) c);CHKERRQ(ierr);
3581   ierr = VecDestroy(&dm->coordinatesLocal);CHKERRQ(ierr);
3582 
3583   dm->coordinatesLocal = c;
3584 
3585   ierr = VecDestroy(&dm->coordinates);CHKERRQ(ierr);
3586   PetscFunctionReturn(0);
3587 }
3588 
3589 #undef __FUNCT__
3590 #define __FUNCT__ "DMGetCoordinates"
3591 /*@
3592   DMGetCoordinates - Gets a global vector with the coordinates associated with the DM.
3593 
3594   Not Collective
3595 
3596   Input Parameter:
3597 . dm - the DM
3598 
3599   Output Parameter:
3600 . c - global coordinate vector
3601 
3602   Note:
3603   This is a borrowed reference, so the user should NOT destroy this vector
3604 
3605   Each process has only the local coordinates (does NOT have the ghost coordinates).
3606 
3607   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
3608   and (x_0,y_0,z_0,x_1,y_1,z_1...)
3609 
3610   Level: intermediate
3611 
3612 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3613 .seealso: DMSetCoordinates(), DMGetCoordinatesLocal(), DMGetCoordinateDM()
3614 @*/
3615 PetscErrorCode DMGetCoordinates(DM dm, Vec *c)
3616 {
3617   PetscErrorCode ierr;
3618 
3619   PetscFunctionBegin;
3620   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3621   PetscValidPointer(c,2);
3622   if (!dm->coordinates && dm->coordinatesLocal) {
3623     DM cdm = NULL;
3624 
3625     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3626     ierr = DMCreateGlobalVector(cdm, &dm->coordinates);CHKERRQ(ierr);
3627     ierr = PetscObjectSetName((PetscObject) dm->coordinates, "coordinates");CHKERRQ(ierr);
3628     ierr = DMLocalToGlobalBegin(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
3629     ierr = DMLocalToGlobalEnd(cdm, dm->coordinatesLocal, INSERT_VALUES, dm->coordinates);CHKERRQ(ierr);
3630   }
3631   *c = dm->coordinates;
3632   PetscFunctionReturn(0);
3633 }
3634 
3635 #undef __FUNCT__
3636 #define __FUNCT__ "DMGetCoordinatesLocal"
3637 /*@
3638   DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the DM.
3639 
3640   Collective on DM
3641 
3642   Input Parameter:
3643 . dm - the DM
3644 
3645   Output Parameter:
3646 . c - coordinate vector
3647 
3648   Note:
3649   This is a borrowed reference, so the user should NOT destroy this vector
3650 
3651   Each process has the local and ghost coordinates
3652 
3653   For DMDA, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...)
3654   and (x_0,y_0,z_0,x_1,y_1,z_1...)
3655 
3656   Level: intermediate
3657 
3658 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3659 .seealso: DMSetCoordinatesLocal(), DMGetCoordinates(), DMSetCoordinates(), DMGetCoordinateDM()
3660 @*/
3661 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c)
3662 {
3663   PetscErrorCode ierr;
3664 
3665   PetscFunctionBegin;
3666   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3667   PetscValidPointer(c,2);
3668   if (!dm->coordinatesLocal && dm->coordinates) {
3669     DM cdm = NULL;
3670 
3671     ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3672     ierr = DMCreateLocalVector(cdm, &dm->coordinatesLocal);CHKERRQ(ierr);
3673     ierr = PetscObjectSetName((PetscObject) dm->coordinatesLocal, "coordinates");CHKERRQ(ierr);
3674     ierr = DMGlobalToLocalBegin(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
3675     ierr = DMGlobalToLocalEnd(cdm, dm->coordinates, INSERT_VALUES, dm->coordinatesLocal);CHKERRQ(ierr);
3676   }
3677   *c = dm->coordinatesLocal;
3678   PetscFunctionReturn(0);
3679 }
3680 
3681 #undef __FUNCT__
3682 #define __FUNCT__ "DMGetCoordinateDM"
3683 /*@
3684   DMGetCoordinateDM - Gets the DM that prescribes coordinate layout and scatters between global and local coordinates
3685 
3686   Collective on DM
3687 
3688   Input Parameter:
3689 . dm - the DM
3690 
3691   Output Parameter:
3692 . cdm - coordinate DM
3693 
3694   Level: intermediate
3695 
3696 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3697 .seealso: DMSetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
3698 @*/
3699 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm)
3700 {
3701   PetscErrorCode ierr;
3702 
3703   PetscFunctionBegin;
3704   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3705   PetscValidPointer(cdm,2);
3706   if (!dm->coordinateDM) {
3707     if (!dm->ops->createcoordinatedm) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unable to create coordinates for this DM");
3708     ierr = (*dm->ops->createcoordinatedm)(dm, &dm->coordinateDM);CHKERRQ(ierr);
3709   }
3710   *cdm = dm->coordinateDM;
3711   PetscFunctionReturn(0);
3712 }
3713 
3714 #undef __FUNCT__
3715 #define __FUNCT__ "DMSetCoordinateDM"
3716 /*@
3717   DMSetCoordinateDM - Sets the DM that prescribes coordinate layout and scatters between global and local coordinates
3718 
3719   Logically Collective on DM
3720 
3721   Input Parameters:
3722 + dm - the DM
3723 - cdm - coordinate DM
3724 
3725   Level: intermediate
3726 
3727 .keywords: distributed array, get, corners, nodes, local indices, coordinates
3728 .seealso: DMGetCoordinateDM(), DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
3729 @*/
3730 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm)
3731 {
3732   PetscErrorCode ierr;
3733 
3734   PetscFunctionBegin;
3735   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3736   PetscValidHeaderSpecific(cdm,DM_CLASSID,2);
3737   ierr = DMDestroy(&dm->coordinateDM);CHKERRQ(ierr);
3738   dm->coordinateDM = cdm;
3739   ierr = PetscObjectReference((PetscObject) dm->coordinateDM);CHKERRQ(ierr);
3740   PetscFunctionReturn(0);
3741 }
3742 
3743 #undef __FUNCT__
3744 #define __FUNCT__ "DMGetCoordinateDim"
3745 /*@
3746   DMGetCoordinateDim - Retrieve the dimension of embedding space for coordinate values.
3747 
3748   Not Collective
3749 
3750   Input Parameter:
3751 . dm - The DM object
3752 
3753   Output Parameter:
3754 . dim - The embedding dimension
3755 
3756   Level: intermediate
3757 
3758 .keywords: mesh, coordinates
3759 .seealso: DMSetCoordinateDim(), DMGetCoordinateSection(), DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
3760 @*/
3761 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim)
3762 {
3763   PetscFunctionBegin;
3764   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3765   PetscValidPointer(dim, 2);
3766   if (dm->dimEmbed == PETSC_DEFAULT) {
3767     dm->dimEmbed = dm->dim;
3768   }
3769   *dim = dm->dimEmbed;
3770   PetscFunctionReturn(0);
3771 }
3772 
3773 #undef __FUNCT__
3774 #define __FUNCT__ "DMSetCoordinateDim"
3775 /*@
3776   DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values.
3777 
3778   Not Collective
3779 
3780   Input Parameters:
3781 + dm  - The DM object
3782 - dim - The embedding dimension
3783 
3784   Level: intermediate
3785 
3786 .keywords: mesh, coordinates
3787 .seealso: DMGetCoordinateDim(), DMSetCoordinateSection(), DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
3788 @*/
3789 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim)
3790 {
3791   PetscFunctionBegin;
3792   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3793   dm->dimEmbed = dim;
3794   PetscFunctionReturn(0);
3795 }
3796 
3797 #undef __FUNCT__
3798 #define __FUNCT__ "DMGetCoordinateSection"
3799 /*@
3800   DMGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
3801 
3802   Not Collective
3803 
3804   Input Parameter:
3805 . dm - The DM object
3806 
3807   Output Parameter:
3808 . section - The PetscSection object
3809 
3810   Level: intermediate
3811 
3812 .keywords: mesh, coordinates
3813 .seealso: DMGetCoordinateDM(), DMGetDefaultSection(), DMSetDefaultSection()
3814 @*/
3815 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section)
3816 {
3817   DM             cdm;
3818   PetscErrorCode ierr;
3819 
3820   PetscFunctionBegin;
3821   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3822   PetscValidPointer(section, 2);
3823   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3824   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
3825   PetscFunctionReturn(0);
3826 }
3827 
3828 #undef __FUNCT__
3829 #define __FUNCT__ "DMSetCoordinateSection"
3830 /*@
3831   DMSetCoordinateSection - Set the layout of coordinate values over the mesh.
3832 
3833   Not Collective
3834 
3835   Input Parameters:
3836 + dm      - The DM object
3837 . dim     - The embedding dimension, or PETSC_DETERMINE
3838 - section - The PetscSection object
3839 
3840   Level: intermediate
3841 
3842 .keywords: mesh, coordinates
3843 .seealso: DMGetCoordinateSection(), DMGetDefaultSection(), DMSetDefaultSection()
3844 @*/
3845 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section)
3846 {
3847   DM             cdm;
3848   PetscErrorCode ierr;
3849 
3850   PetscFunctionBegin;
3851   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3852   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,3);
3853   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
3854   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
3855   if (dim == PETSC_DETERMINE) {
3856     PetscInt d = dim;
3857     PetscInt pStart, pEnd, vStart, vEnd, v, dd;
3858 
3859     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
3860     ierr = DMGetDimPoints(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3861     pStart = PetscMax(vStart, pStart);
3862     pEnd   = PetscMin(vEnd, pEnd);
3863     for (v = pStart; v < pEnd; ++v) {
3864       ierr = PetscSectionGetDof(section, v, &dd);CHKERRQ(ierr);
3865       if (dd) {d = dd; break;}
3866     }
3867     ierr = DMSetCoordinateDim(dm, d);CHKERRQ(ierr);
3868   }
3869   PetscFunctionReturn(0);
3870 }
3871 
3872 #undef __FUNCT__
3873 #define __FUNCT__ "DMGetPeriodicity"
3874 PetscErrorCode DMGetPeriodicity(DM dm, const PetscReal **maxCell, const PetscReal **L)
3875 {
3876   PetscFunctionBegin;
3877   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3878   if (L)       *L       = dm->L;
3879   if (maxCell) *maxCell = dm->maxCell;
3880   PetscFunctionReturn(0);
3881 }
3882 
3883 #undef __FUNCT__
3884 #define __FUNCT__ "DMSetPeriodicity"
3885 PetscErrorCode DMSetPeriodicity(DM dm, const PetscReal maxCell[], const PetscReal L[])
3886 {
3887   Vec            coordinates;
3888   PetscInt       dim, d;
3889   PetscErrorCode ierr;
3890 
3891   PetscFunctionBegin;
3892   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3893   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3894   ierr = VecGetBlockSize(coordinates, &dim);CHKERRQ(ierr);
3895   ierr = PetscMalloc1(dim,&dm->L);CHKERRQ(ierr);
3896   ierr = PetscMalloc1(dim,&dm->maxCell);CHKERRQ(ierr);
3897   for (d = 0; d < dim; ++d) {dm->L[d] = L[d]; dm->maxCell[d] = maxCell[d];}
3898   PetscFunctionReturn(0);
3899 }
3900 
3901 #undef __FUNCT__
3902 #define __FUNCT__ "DMLocatePoints"
3903 /*@
3904   DMLocatePoints - Locate the points in v in the mesh and return an IS of the containing cells
3905 
3906   Not collective
3907 
3908   Input Parameters:
3909 + dm - The DM
3910 - v - The Vec of points
3911 
3912   Output Parameter:
3913 . cells - The local cell numbers for cells which contain the points
3914 
3915   Level: developer
3916 
3917 .keywords: point location, mesh
3918 .seealso: DMSetCoordinates(), DMSetCoordinatesLocal(), DMGetCoordinates(), DMGetCoordinatesLocal()
3919 @*/
3920 PetscErrorCode DMLocatePoints(DM dm, Vec v, IS *cells)
3921 {
3922   PetscErrorCode ierr;
3923 
3924   PetscFunctionBegin;
3925   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3926   PetscValidHeaderSpecific(v,VEC_CLASSID,2);
3927   PetscValidPointer(cells,3);
3928   if (dm->ops->locatepoints) {
3929     ierr = (*dm->ops->locatepoints)(dm,v,cells);CHKERRQ(ierr);
3930   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Point location not available for this DM");
3931   PetscFunctionReturn(0);
3932 }
3933 
3934 #undef __FUNCT__
3935 #define __FUNCT__ "DMGetOutputDM"
3936 /*@
3937   DMGetOutputDM - Retrieve the DM associated with the layout for output
3938 
3939   Input Parameter:
3940 . dm - The original DM
3941 
3942   Output Parameter:
3943 . odm - The DM which provides the layout for output
3944 
3945   Level: intermediate
3946 
3947 .seealso: VecView(), DMGetDefaultGlobalSection()
3948 @*/
3949 PetscErrorCode DMGetOutputDM(DM dm, DM *odm)
3950 {
3951   PetscSection   section;
3952   PetscBool      hasConstraints;
3953   PetscErrorCode ierr;
3954 
3955   PetscFunctionBegin;
3956   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3957   PetscValidPointer(odm,2);
3958   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
3959   ierr = PetscSectionHasConstraints(section, &hasConstraints);CHKERRQ(ierr);
3960   if (!hasConstraints) {
3961     *odm = dm;
3962     PetscFunctionReturn(0);
3963   }
3964   if (!dm->dmBC) {
3965     PetscSection newSection, gsection;
3966     PetscSF      sf;
3967 
3968     ierr = DMClone(dm, &dm->dmBC);CHKERRQ(ierr);
3969     ierr = PetscSectionClone(section, &newSection);CHKERRQ(ierr);
3970     ierr = DMSetDefaultSection(dm->dmBC, newSection);CHKERRQ(ierr);
3971     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
3972     ierr = DMGetPointSF(dm->dmBC, &sf);CHKERRQ(ierr);
3973     ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, &gsection);CHKERRQ(ierr);
3974     ierr = DMSetDefaultGlobalSection(dm->dmBC, gsection);CHKERRQ(ierr);
3975     ierr = PetscSectionDestroy(&gsection);CHKERRQ(ierr);
3976   }
3977   *odm = dm->dmBC;
3978   PetscFunctionReturn(0);
3979 }
3980 
3981 #undef __FUNCT__
3982 #define __FUNCT__ "DMGetOutputSequenceNumber"
3983 /*@
3984   DMGetOutputSequenceNumber - Retrieve the sequence number/value for output
3985 
3986   Input Parameter:
3987 . dm - The original DM
3988 
3989   Output Parameters:
3990 + num - The output sequence number
3991 - val - The output sequence value
3992 
3993   Level: intermediate
3994 
3995   Note: This is intended for output that should appear in sequence, for instance
3996   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
3997 
3998 .seealso: VecView()
3999 @*/
4000 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val)
4001 {
4002   PetscFunctionBegin;
4003   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4004   if (num) {PetscValidPointer(num,2); *num = dm->outputSequenceNum;}
4005   if (val) {PetscValidPointer(val,3);*val = dm->outputSequenceVal;}
4006   PetscFunctionReturn(0);
4007 }
4008 
4009 #undef __FUNCT__
4010 #define __FUNCT__ "DMSetOutputSequenceNumber"
4011 /*@
4012   DMSetOutputSequenceNumber - Set the sequence number/value for output
4013 
4014   Input Parameters:
4015 + dm - The original DM
4016 . num - The output sequence number
4017 - val - The output sequence value
4018 
4019   Level: intermediate
4020 
4021   Note: This is intended for output that should appear in sequence, for instance
4022   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4023 
4024 .seealso: VecView()
4025 @*/
4026 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val)
4027 {
4028   PetscFunctionBegin;
4029   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4030   dm->outputSequenceNum = num;
4031   dm->outputSequenceVal = val;
4032   PetscFunctionReturn(0);
4033 }
4034 
4035 #undef __FUNCT__
4036 #define __FUNCT__ "DMOutputSequenceLoad"
4037 /*@C
4038   DMOutputSequenceLoad - Retrieve the sequence value from a Viewer
4039 
4040   Input Parameters:
4041 + dm   - The original DM
4042 . name - The sequence name
4043 - num  - The output sequence number
4044 
4045   Output Parameter:
4046 . val  - The output sequence value
4047 
4048   Level: intermediate
4049 
4050   Note: This is intended for output that should appear in sequence, for instance
4051   a set of timesteps in an HDF5 file, or a set of realizations of a stochastic system.
4052 
4053 .seealso: DMGetOutputSequenceNumber(), DMSetOutputSequenceNumber(), VecView()
4054 @*/
4055 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val)
4056 {
4057   PetscBool      ishdf5;
4058   PetscErrorCode ierr;
4059 
4060   PetscFunctionBegin;
4061   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4062   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
4063   PetscValidPointer(val,4);
4064   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5);CHKERRQ(ierr);
4065   if (ishdf5) {
4066 #if defined(PETSC_HAVE_HDF5)
4067     PetscScalar value;
4068 
4069     ierr = DMSequenceLoad_HDF5(dm, name, num, &value, viewer);CHKERRQ(ierr);
4070     *val = PetscRealPart(value);
4071 #endif
4072   } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()");
4073   PetscFunctionReturn(0);
4074 }
4075