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