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