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