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