xref: /petsc/src/dm/impls/da/da.c (revision 4eb7a547ccbe6f119b83b2bfced6293e5b2e2593)
1 #include <petsc/private/dmdaimpl.h>    /*I   "petscdmda.h"   I*/
2 
3 #undef __FUNCT__
4 #define __FUNCT__ "DMDASetSizes"
5 /*@
6   DMDASetSizes - Sets the global sizes
7 
8   Logically Collective on DMDA
9 
10   Input Parameters:
11 + da - the DMDA
12 . M - the global X size (or PETSC_DECIDE)
13 . N - the global Y size (or PETSC_DECIDE)
14 - P - the global Z size (or PETSC_DECIDE)
15 
16   Level: intermediate
17 
18 .seealso: DMDAGetSize(), PetscSplitOwnership()
19 @*/
20 PetscErrorCode  DMDASetSizes(DM da, PetscInt M, PetscInt N, PetscInt P)
21 {
22   DM_DA *dd = (DM_DA*)da->data;
23 
24   PetscFunctionBegin;
25   PetscValidHeaderSpecific(da, DM_CLASSID, 1);
26   PetscValidLogicalCollectiveInt(da,M,2);
27   PetscValidLogicalCollectiveInt(da,N,3);
28   PetscValidLogicalCollectiveInt(da,P,4);
29   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
30 
31   dd->M = M;
32   dd->N = N;
33   dd->P = P;
34   PetscFunctionReturn(0);
35 }
36 
37 #undef __FUNCT__
38 #define __FUNCT__ "DMDASetNumProcs"
39 /*@
40   DMDASetNumProcs - Sets the number of processes in each dimension
41 
42   Logically Collective on DMDA
43 
44   Input Parameters:
45 + da - the DMDA
46 . m - the number of X procs (or PETSC_DECIDE)
47 . n - the number of Y procs (or PETSC_DECIDE)
48 - p - the number of Z procs (or PETSC_DECIDE)
49 
50   Level: intermediate
51 
52 .seealso: DMDASetSizes(), DMDAGetSize(), PetscSplitOwnership()
53 @*/
54 PetscErrorCode  DMDASetNumProcs(DM da, PetscInt m, PetscInt n, PetscInt p)
55 {
56   DM_DA          *dd = (DM_DA*)da->data;
57   PetscErrorCode ierr;
58 
59   PetscFunctionBegin;
60   PetscValidHeaderSpecific(da, DM_CLASSID, 1);
61   PetscValidLogicalCollectiveInt(da,m,2);
62   PetscValidLogicalCollectiveInt(da,n,3);
63   PetscValidLogicalCollectiveInt(da,p,4);
64   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
65   dd->m = m;
66   dd->n = n;
67   dd->p = p;
68   if (da->dim == 2) {
69     PetscMPIInt size;
70     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)da),&size);CHKERRQ(ierr);
71     if ((dd->m > 0) && (dd->n < 0)) {
72       dd->n = size/dd->m;
73       if (dd->n*dd->m != size) SETERRQ2(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"%D processes in X direction not divisible into comm size %d",m,size);
74     }
75     if ((dd->n > 0) && (dd->m < 0)) {
76       dd->m = size/dd->n;
77       if (dd->n*dd->m != size) SETERRQ2(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"%D processes in Y direction not divisible into comm size %d",n,size);
78     }
79   }
80   PetscFunctionReturn(0);
81 }
82 
83 #undef __FUNCT__
84 #define __FUNCT__ "DMDASetBoundaryType"
85 /*@
86   DMDASetBoundaryType - Sets the type of ghost nodes on domain boundaries.
87 
88   Not collective
89 
90   Input Parameter:
91 + da    - The DMDA
92 - bx,by,bz - One of DM_BOUNDARY_NONE, DM_BOUNDARY_GHOSTED, DM_BOUNDARY_PERIODIC
93 
94   Level: intermediate
95 
96 .keywords:  distributed array, periodicity
97 .seealso: DMDACreate(), DMDestroy(), DMDA, DMBoundaryType
98 @*/
99 PetscErrorCode  DMDASetBoundaryType(DM da,DMBoundaryType bx,DMBoundaryType by,DMBoundaryType bz)
100 {
101   DM_DA *dd = (DM_DA*)da->data;
102 
103   PetscFunctionBegin;
104   PetscValidHeaderSpecific(da,DM_CLASSID,1);
105   PetscValidLogicalCollectiveEnum(da,bx,2);
106   PetscValidLogicalCollectiveEnum(da,by,3);
107   PetscValidLogicalCollectiveEnum(da,bz,4);
108   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
109   dd->bx = bx;
110   dd->by = by;
111   dd->bz = bz;
112   PetscFunctionReturn(0);
113 }
114 
115 #undef __FUNCT__
116 #define __FUNCT__ "DMDASetDof"
117 /*@
118   DMDASetDof - Sets the number of degrees of freedom per vertex
119 
120   Not collective
121 
122   Input Parameters:
123 + da  - The DMDA
124 - dof - Number of degrees of freedom
125 
126   Level: intermediate
127 
128 .keywords:  distributed array, degrees of freedom
129 .seealso: DMDAGetDof(), DMDACreate(), DMDestroy(), DMDA
130 @*/
131 PetscErrorCode  DMDASetDof(DM da, PetscInt dof)
132 {
133   DM_DA *dd = (DM_DA*)da->data;
134 
135   PetscFunctionBegin;
136   PetscValidHeaderSpecific(da,DM_CLASSID,1);
137   PetscValidLogicalCollectiveInt(da,dof,2);
138   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
139   dd->w  = dof;
140   da->bs = dof;
141   PetscFunctionReturn(0);
142 }
143 
144 #undef __FUNCT__
145 #define __FUNCT__ "DMDAGetDof"
146 /*@
147   DMDAGetDof - Gets the number of degrees of freedom per vertex
148 
149   Not collective
150 
151   Input Parameter:
152 . da  - The DMDA
153 
154   Output Parameter:
155 . dof - Number of degrees of freedom
156 
157   Level: intermediate
158 
159 .keywords:  distributed array, degrees of freedom
160 .seealso: DMDASetDof(), DMDACreate(), DMDestroy(), DMDA
161 @*/
162 PetscErrorCode DMDAGetDof(DM da, PetscInt *dof)
163 {
164   DM_DA *dd = (DM_DA *) da->data;
165 
166   PetscFunctionBegin;
167   PetscValidHeaderSpecific(da,DM_CLASSID,1);
168   PetscValidPointer(dof,2);
169   *dof = dd->w;
170   PetscFunctionReturn(0);
171 }
172 
173 #undef __FUNCT__
174 #define __FUNCT__ "DMDAGetOverlap"
175 /*@
176   DMDAGetOverlap - Gets the size of the per-processor overlap.
177 
178   Not collective
179 
180   Input Parameters:
181 . da  - The DMDA
182 
183   Output Parameters:
184 + x   - Overlap in the x direction
185 . y   - Overlap in the y direction
186 - z   - Overlap in the z direction
187 
188   Level: intermediate
189 
190 .keywords:  distributed array, overlap, domain decomposition
191 .seealso: DMDACreateDomainDecomposition(), DMDASetOverlap(), DMDA
192 @*/
193 PetscErrorCode  DMDAGetOverlap(DM da,PetscInt *x,PetscInt *y,PetscInt *z)
194 {
195   DM_DA *dd = (DM_DA*)da->data;
196 
197   PetscFunctionBegin;
198   PetscValidHeaderSpecific(da,DM_CLASSID,1);
199   if (x) *x = dd->xol;
200   if (y) *y = dd->yol;
201   if (z) *z = dd->zol;
202   PetscFunctionReturn(0);
203 }
204 
205 #undef __FUNCT__
206 #define __FUNCT__ "DMDASetOverlap"
207 /*@
208   DMDASetOverlap - Sets the size of the per-processor overlap.
209 
210   Not collective
211 
212   Input Parameters:
213 + da  - The DMDA
214 . x   - Overlap in the x direction
215 . y   - Overlap in the y direction
216 - z   - Overlap in the z direction
217 
218   Level: intermediate
219 
220 .keywords:  distributed array, overlap, domain decomposition
221 .seealso: DMDACreateDomainDecomposition(), DMDAGetOverlap(), DMDA
222 @*/
223 PetscErrorCode  DMDASetOverlap(DM da,PetscInt x,PetscInt y,PetscInt z)
224 {
225   DM_DA *dd = (DM_DA*)da->data;
226 
227   PetscFunctionBegin;
228   PetscValidHeaderSpecific(da,DM_CLASSID,1);
229   PetscValidLogicalCollectiveInt(da,x,2);
230   PetscValidLogicalCollectiveInt(da,y,3);
231   PetscValidLogicalCollectiveInt(da,z,4);
232   dd->xol = x;
233   dd->yol = y;
234   dd->zol = z;
235   PetscFunctionReturn(0);
236 }
237 
238 
239 #undef __FUNCT__
240 #define __FUNCT__ "DMDAGetNumLocalSubDomains"
241 /*@
242   DMDAGetNumLocalSubDomains - Gets the number of local subdomains created upon decomposition.
243 
244   Not collective
245 
246   Input Parameters:
247 . da  - The DMDA
248 
249   Output Parameters:
250 + Nsub   - Number of local subdomains created upon decomposition
251 
252   Level: intermediate
253 
254 .keywords:  distributed array, domain decomposition
255 .seealso: DMDACreateDomainDecomposition(), DMDASetNumLocalSubDomains(), DMDA
256 @*/
257 PetscErrorCode  DMDAGetNumLocalSubDomains(DM da,PetscInt *Nsub)
258 {
259   DM_DA *dd = (DM_DA*)da->data;
260 
261   PetscFunctionBegin;
262   PetscValidHeaderSpecific(da,DM_CLASSID,1);
263   if (Nsub) *Nsub = dd->Nsub;
264   PetscFunctionReturn(0);
265 }
266 
267 #undef __FUNCT__
268 #define __FUNCT__ "DMDASetNumLocalSubDomains"
269 /*@
270   DMDASetNumLocalSubDomains - Sets the number of local subdomains created upon decomposition.
271 
272   Not collective
273 
274   Input Parameters:
275 + da  - The DMDA
276 - Nsub - The number of local subdomains requested
277 
278   Level: intermediate
279 
280 .keywords:  distributed array, domain decomposition
281 .seealso: DMDACreateDomainDecomposition(), DMDAGetNumLocalSubDomains(), DMDA
282 @*/
283 PetscErrorCode  DMDASetNumLocalSubDomains(DM da,PetscInt Nsub)
284 {
285   DM_DA *dd = (DM_DA*)da->data;
286 
287   PetscFunctionBegin;
288   PetscValidHeaderSpecific(da,DM_CLASSID,1);
289   PetscValidLogicalCollectiveInt(da,Nsub,2);
290   dd->Nsub = Nsub;
291   PetscFunctionReturn(0);
292 }
293 
294 #undef __FUNCT__
295 #define __FUNCT__ "DMDASetOffset"
296 /*@
297   DMDASetOffset - Sets the index offset of the DA.
298 
299   Collective on DA
300 
301   Input Parameter:
302 + da  - The DMDA
303 . xo  - The offset in the x direction
304 . yo  - The offset in the y direction
305 - zo  - The offset in the z direction
306 
307   Level: intermediate
308 
309   Notes: This is used primarily to overlap a computation on a local DA with that on a global DA without
310   changing boundary conditions or subdomain features that depend upon the global offsets.
311 
312 .keywords:  distributed array, degrees of freedom
313 .seealso: DMDAGetOffset(), DMDAVecGetArray()
314 @*/
315 PetscErrorCode  DMDASetOffset(DM da, PetscInt xo, PetscInt yo, PetscInt zo, PetscInt Mo, PetscInt No, PetscInt Po)
316 {
317   PetscErrorCode ierr;
318   DM_DA          *dd = (DM_DA*)da->data;
319 
320   PetscFunctionBegin;
321   PetscValidHeaderSpecific(da,DM_CLASSID,1);
322   PetscValidLogicalCollectiveInt(da,xo,2);
323   PetscValidLogicalCollectiveInt(da,yo,3);
324   PetscValidLogicalCollectiveInt(da,zo,4);
325   PetscValidLogicalCollectiveInt(da,Mo,5);
326   PetscValidLogicalCollectiveInt(da,No,6);
327   PetscValidLogicalCollectiveInt(da,Po,7);
328   dd->xo = xo;
329   dd->yo = yo;
330   dd->zo = zo;
331   dd->Mo = Mo;
332   dd->No = No;
333   dd->Po = Po;
334 
335   if (da->coordinateDM) {
336     ierr = DMDASetOffset(da->coordinateDM,xo,yo,zo,Mo,No,Po);CHKERRQ(ierr);
337   }
338   PetscFunctionReturn(0);
339 }
340 
341 #undef __FUNCT__
342 #define __FUNCT__ "DMDAGetOffset"
343 /*@
344   DMDAGetOffset - Gets the index offset of the DA.
345 
346   Not collective
347 
348   Input Parameter:
349 . da  - The DMDA
350 
351   Output Parameters:
352 + xo  - The offset in the x direction
353 . yo  - The offset in the y direction
354 . zo  - The offset in the z direction
355 . Mo  - The global size in the x direction
356 . No  - The global size in the y direction
357 - Po  - The global size in the z direction
358 
359   Level: intermediate
360 
361 .keywords:  distributed array, degrees of freedom
362 .seealso: DMDASetOffset(), DMDAVecGetArray()
363 @*/
364 PetscErrorCode  DMDAGetOffset(DM da,PetscInt *xo,PetscInt *yo,PetscInt *zo,PetscInt *Mo,PetscInt *No,PetscInt *Po)
365 {
366   DM_DA *dd = (DM_DA*)da->data;
367 
368   PetscFunctionBegin;
369   PetscValidHeaderSpecific(da,DM_CLASSID,1);
370   if (xo) *xo = dd->xo;
371   if (yo) *yo = dd->yo;
372   if (zo) *zo = dd->zo;
373   if (Mo) *Mo = dd->Mo;
374   if (No) *No = dd->No;
375   if (Po) *Po = dd->Po;
376   PetscFunctionReturn(0);
377 }
378 
379 #undef __FUNCT__
380 #define __FUNCT__ "DMDAGetNonOverlappingRegion"
381 /*@
382   DMDAGetNonOverlappingRegion - Gets the indices of the nonoverlapping region of a subdomain DM.
383 
384   Not collective
385 
386   Input Parameter:
387 . da  - The DMDA
388 
389   Output Parameters:
390 + xs  - The start of the region in x
391 . ys  - The start of the region in y
392 . zs  - The start of the region in z
393 . xs  - The size of the region in x
394 . ys  - The size of the region in y
395 . zs  - The size of the region in z
396 
397   Level: intermediate
398 
399 .keywords:  distributed array, degrees of freedom
400 .seealso: DMDAGetOffset(), DMDAVecGetArray()
401 @*/
402 PetscErrorCode  DMDAGetNonOverlappingRegion(DM da, PetscInt *xs, PetscInt *ys, PetscInt *zs, PetscInt *xm, PetscInt *ym, PetscInt *zm)
403 {
404   DM_DA          *dd = (DM_DA*)da->data;
405 
406   PetscFunctionBegin;
407   PetscValidHeaderSpecific(da,DM_CLASSID,1);
408   if (xs) *xs = dd->nonxs;
409   if (ys) *ys = dd->nonys;
410   if (zs) *zs = dd->nonzs;
411   if (xm) *xm = dd->nonxm;
412   if (ym) *ym = dd->nonym;
413   if (zm) *zm = dd->nonzm;
414   PetscFunctionReturn(0);
415 }
416 
417 
418 #undef __FUNCT__
419 #define __FUNCT__ "DMDASetNonOverlappingRegion"
420 /*@
421   DMDASetNonOverlappingRegion - Sets the indices of the nonoverlapping region of a subdomain DM.
422 
423   Collective on DA
424 
425   Input Parameter:
426 + da  - The DMDA
427 . xs  - The start of the region in x
428 . ys  - The start of the region in y
429 . zs  - The start of the region in z
430 . xs  - The size of the region in x
431 . ys  - The size of the region in y
432 . zs  - The size of the region in z
433 
434   Level: intermediate
435 
436 .keywords:  distributed array, degrees of freedom
437 .seealso: DMDAGetOffset(), DMDAVecGetArray()
438 @*/
439 PetscErrorCode  DMDASetNonOverlappingRegion(DM da, PetscInt xs, PetscInt ys, PetscInt zs, PetscInt xm, PetscInt ym, PetscInt zm)
440 {
441   DM_DA          *dd = (DM_DA*)da->data;
442 
443   PetscFunctionBegin;
444   PetscValidHeaderSpecific(da,DM_CLASSID,1);
445   PetscValidLogicalCollectiveInt(da,xs,2);
446   PetscValidLogicalCollectiveInt(da,ys,3);
447   PetscValidLogicalCollectiveInt(da,zs,4);
448   PetscValidLogicalCollectiveInt(da,xm,5);
449   PetscValidLogicalCollectiveInt(da,ym,6);
450   PetscValidLogicalCollectiveInt(da,zm,7);
451   dd->nonxs = xs;
452   dd->nonys = ys;
453   dd->nonzs = zs;
454   dd->nonxm = xm;
455   dd->nonym = ym;
456   dd->nonzm = zm;
457 
458   PetscFunctionReturn(0);
459 }
460 
461 #undef __FUNCT__
462 #define __FUNCT__ "DMDASetStencilType"
463 /*@
464   DMDASetStencilType - Sets the type of the communication stencil
465 
466   Logically Collective on DMDA
467 
468   Input Parameter:
469 + da    - The DMDA
470 - stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
471 
472   Level: intermediate
473 
474 .keywords:  distributed array, stencil
475 .seealso: DMDACreate(), DMDestroy(), DMDA
476 @*/
477 PetscErrorCode  DMDASetStencilType(DM da, DMDAStencilType stype)
478 {
479   DM_DA *dd = (DM_DA*)da->data;
480 
481   PetscFunctionBegin;
482   PetscValidHeaderSpecific(da,DM_CLASSID,1);
483   PetscValidLogicalCollectiveEnum(da,stype,2);
484   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
485   dd->stencil_type = stype;
486   PetscFunctionReturn(0);
487 }
488 
489 #undef __FUNCT__
490 #define __FUNCT__ "DMDAGetStencilType"
491 /*@
492   DMDAGetStencilType - Gets the type of the communication stencil
493 
494   Not collective
495 
496   Input Parameter:
497 . da    - The DMDA
498 
499   Output Parameter:
500 . stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
501 
502   Level: intermediate
503 
504 .keywords:  distributed array, stencil
505 .seealso: DMDACreate(), DMDestroy(), DMDA
506 @*/
507 PetscErrorCode DMDAGetStencilType(DM da, DMDAStencilType *stype)
508 {
509   DM_DA *dd = (DM_DA*)da->data;
510 
511   PetscFunctionBegin;
512   PetscValidHeaderSpecific(da,DM_CLASSID,1);
513   PetscValidPointer(stype,2);
514   *stype = dd->stencil_type;
515   PetscFunctionReturn(0);
516 }
517 
518 #undef __FUNCT__
519 #define __FUNCT__ "DMDASetStencilWidth"
520 /*@
521   DMDASetStencilWidth - Sets the width of the communication stencil
522 
523   Logically Collective on DMDA
524 
525   Input Parameter:
526 + da    - The DMDA
527 - width - The stencil width
528 
529   Level: intermediate
530 
531 .keywords:  distributed array, stencil
532 .seealso: DMDACreate(), DMDestroy(), DMDA
533 @*/
534 PetscErrorCode  DMDASetStencilWidth(DM da, PetscInt width)
535 {
536   DM_DA *dd = (DM_DA*)da->data;
537 
538   PetscFunctionBegin;
539   PetscValidHeaderSpecific(da,DM_CLASSID,1);
540   PetscValidLogicalCollectiveInt(da,width,2);
541   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
542   dd->s = width;
543   PetscFunctionReturn(0);
544 }
545 
546 #undef __FUNCT__
547 #define __FUNCT__ "DMDAGetStencilWidth"
548 /*@
549   DMDAGetStencilWidth - Gets the width of the communication stencil
550 
551   Not collective
552 
553   Input Parameter:
554 . da    - The DMDA
555 
556   Output Parameter:
557 . width - The stencil width
558 
559   Level: intermediate
560 
561 .keywords:  distributed array, stencil
562 .seealso: DMDACreate(), DMDestroy(), DMDA
563 @*/
564 PetscErrorCode DMDAGetStencilWidth(DM da, PetscInt *width)
565 {
566   DM_DA *dd = (DM_DA *) da->data;
567 
568   PetscFunctionBegin;
569   PetscValidHeaderSpecific(da,DM_CLASSID,1);
570   PetscValidPointer(width,2);
571   *width = dd->s;
572   PetscFunctionReturn(0);
573 }
574 
575 #undef __FUNCT__
576 #define __FUNCT__ "DMDACheckOwnershipRanges_Private"
577 static PetscErrorCode DMDACheckOwnershipRanges_Private(DM da,PetscInt M,PetscInt m,const PetscInt lx[])
578 {
579   PetscInt i,sum;
580 
581   PetscFunctionBegin;
582   if (M < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Global dimension not set");
583   for (i=sum=0; i<m; i++) sum += lx[i];
584   if (sum != M) SETERRQ2(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_INCOMP,"Ownership ranges sum to %D but global dimension is %D",sum,M);
585   PetscFunctionReturn(0);
586 }
587 
588 #undef __FUNCT__
589 #define __FUNCT__ "DMDASetOwnershipRanges"
590 /*@
591   DMDASetOwnershipRanges - Sets the number of nodes in each direction on each process
592 
593   Logically Collective on DMDA
594 
595   Input Parameter:
596 + da - The DMDA
597 . lx - array containing number of nodes in the X direction on each process, or NULL. If non-null, must be of length da->m
598 . ly - array containing number of nodes in the Y direction on each process, or NULL. If non-null, must be of length da->n
599 - lz - array containing number of nodes in the Z direction on each process, or NULL. If non-null, must be of length da->p.
600 
601   Level: intermediate
602 
603   Note: these numbers are NOT multiplied by the number of dof per node.
604 
605 .keywords:  distributed array
606 .seealso: DMDACreate(), DMDestroy(), DMDA
607 @*/
608 PetscErrorCode  DMDASetOwnershipRanges(DM da, const PetscInt lx[], const PetscInt ly[], const PetscInt lz[])
609 {
610   PetscErrorCode ierr;
611   DM_DA          *dd = (DM_DA*)da->data;
612 
613   PetscFunctionBegin;
614   PetscValidHeaderSpecific(da,DM_CLASSID,1);
615   if (da->setupcalled) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"This function must be called before DMSetUp()");
616   if (lx) {
617     if (dd->m < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
618     ierr = DMDACheckOwnershipRanges_Private(da,dd->M,dd->m,lx);CHKERRQ(ierr);
619     if (!dd->lx) {
620       ierr = PetscMalloc1(dd->m, &dd->lx);CHKERRQ(ierr);
621     }
622     ierr = PetscMemcpy(dd->lx, lx, dd->m*sizeof(PetscInt));CHKERRQ(ierr);
623   }
624   if (ly) {
625     if (dd->n < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
626     ierr = DMDACheckOwnershipRanges_Private(da,dd->N,dd->n,ly);CHKERRQ(ierr);
627     if (!dd->ly) {
628       ierr = PetscMalloc1(dd->n, &dd->ly);CHKERRQ(ierr);
629     }
630     ierr = PetscMemcpy(dd->ly, ly, dd->n*sizeof(PetscInt));CHKERRQ(ierr);
631   }
632   if (lz) {
633     if (dd->p < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
634     ierr = DMDACheckOwnershipRanges_Private(da,dd->P,dd->p,lz);CHKERRQ(ierr);
635     if (!dd->lz) {
636       ierr = PetscMalloc1(dd->p, &dd->lz);CHKERRQ(ierr);
637     }
638     ierr = PetscMemcpy(dd->lz, lz, dd->p*sizeof(PetscInt));CHKERRQ(ierr);
639   }
640   PetscFunctionReturn(0);
641 }
642 
643 #undef __FUNCT__
644 #define __FUNCT__ "DMDASetInterpolationType"
645 /*@
646        DMDASetInterpolationType - Sets the type of interpolation that will be
647           returned by DMCreateInterpolation()
648 
649    Logically Collective on DMDA
650 
651    Input Parameter:
652 +  da - initial distributed array
653 .  ctype - DMDA_Q1 and DMDA_Q0 are currently the only supported forms
654 
655    Level: intermediate
656 
657    Notes: you should call this on the coarser of the two DMDAs you pass to DMCreateInterpolation()
658 
659 .keywords:  distributed array, interpolation
660 
661 .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType
662 @*/
663 PetscErrorCode  DMDASetInterpolationType(DM da,DMDAInterpolationType ctype)
664 {
665   DM_DA *dd = (DM_DA*)da->data;
666 
667   PetscFunctionBegin;
668   PetscValidHeaderSpecific(da,DM_CLASSID,1);
669   PetscValidLogicalCollectiveEnum(da,ctype,2);
670   dd->interptype = ctype;
671   PetscFunctionReturn(0);
672 }
673 
674 #undef __FUNCT__
675 #define __FUNCT__ "DMDAGetInterpolationType"
676 /*@
677        DMDAGetInterpolationType - Gets the type of interpolation that will be
678           used by DMCreateInterpolation()
679 
680    Not Collective
681 
682    Input Parameter:
683 .  da - distributed array
684 
685    Output Parameter:
686 .  ctype - interpolation type (DMDA_Q1 and DMDA_Q0 are currently the only supported forms)
687 
688    Level: intermediate
689 
690 .keywords:  distributed array, interpolation
691 
692 .seealso: DMDA, DMDAInterpolationType, DMDASetInterpolationType(), DMCreateInterpolation()
693 @*/
694 PetscErrorCode  DMDAGetInterpolationType(DM da,DMDAInterpolationType *ctype)
695 {
696   DM_DA *dd = (DM_DA*)da->data;
697 
698   PetscFunctionBegin;
699   PetscValidHeaderSpecific(da,DM_CLASSID,1);
700   PetscValidPointer(ctype,2);
701   *ctype = dd->interptype;
702   PetscFunctionReturn(0);
703 }
704 
705 #undef __FUNCT__
706 #define __FUNCT__ "DMDAGetNeighbors"
707 /*@C
708       DMDAGetNeighbors - Gets an array containing the MPI rank of all the current
709         processes neighbors.
710 
711     Not Collective
712 
713    Input Parameter:
714 .     da - the DMDA object
715 
716    Output Parameters:
717 .     ranks - the neighbors ranks, stored with the x index increasing most rapidly.
718               this process itself is in the list
719 
720    Notes: In 2d the array is of length 9, in 3d of length 27
721           Not supported in 1d
722           Do not free the array, it is freed when the DMDA is destroyed.
723 
724    Fortran Notes: In fortran you must pass in an array of the appropriate length.
725 
726    Level: intermediate
727 
728 @*/
729 PetscErrorCode  DMDAGetNeighbors(DM da,const PetscMPIInt *ranks[])
730 {
731   DM_DA *dd = (DM_DA*)da->data;
732 
733   PetscFunctionBegin;
734   PetscValidHeaderSpecific(da,DM_CLASSID,1);
735   *ranks = dd->neighbors;
736   PetscFunctionReturn(0);
737 }
738 
739 #undef __FUNCT__
740 #define __FUNCT__ "DMDAGetOwnershipRanges"
741 /*@C
742       DMDAGetOwnershipRanges - Gets the ranges of indices in the x, y and z direction that are owned by each process
743 
744     Not Collective
745 
746    Input Parameter:
747 .     da - the DMDA object
748 
749    Output Parameter:
750 +     lx - ownership along x direction (optional)
751 .     ly - ownership along y direction (optional)
752 -     lz - ownership along z direction (optional)
753 
754    Level: intermediate
755 
756     Note: these correspond to the optional final arguments passed to DMDACreate(), DMDACreate2d(), DMDACreate3d()
757 
758     In Fortran one must pass in arrays lx, ly, and lz that are long enough to hold the values; the sixth, seventh and
759     eighth arguments from DMDAGetInfo()
760 
761      In C you should not free these arrays, nor change the values in them. They will only have valid values while the
762     DMDA they came from still exists (has not been destroyed).
763 
764     These numbers are NOT multiplied by the number of dof per node.
765 
766 .seealso: DMDAGetCorners(), DMDAGetGhostCorners(), DMDACreate(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), VecGetOwnershipRanges()
767 @*/
768 PetscErrorCode  DMDAGetOwnershipRanges(DM da,const PetscInt *lx[],const PetscInt *ly[],const PetscInt *lz[])
769 {
770   DM_DA *dd = (DM_DA*)da->data;
771 
772   PetscFunctionBegin;
773   PetscValidHeaderSpecific(da,DM_CLASSID,1);
774   if (lx) *lx = dd->lx;
775   if (ly) *ly = dd->ly;
776   if (lz) *lz = dd->lz;
777   PetscFunctionReturn(0);
778 }
779 
780 #undef __FUNCT__
781 #define __FUNCT__ "DMDASetRefinementFactor"
782 /*@
783      DMDASetRefinementFactor - Set the ratios that the DMDA grid is refined
784 
785     Logically Collective on DMDA
786 
787   Input Parameters:
788 +    da - the DMDA object
789 .    refine_x - ratio of fine grid to coarse in x direction (2 by default)
790 .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
791 -    refine_z - ratio of fine grid to coarse in z direction (2 by default)
792 
793   Options Database:
794 +  -da_refine_x - refinement ratio in x direction
795 .  -da_refine_y - refinement ratio in y direction
796 -  -da_refine_z - refinement ratio in z direction
797 
798   Level: intermediate
799 
800     Notes: Pass PETSC_IGNORE to leave a value unchanged
801 
802 .seealso: DMRefine(), DMDAGetRefinementFactor()
803 @*/
804 PetscErrorCode  DMDASetRefinementFactor(DM da, PetscInt refine_x, PetscInt refine_y,PetscInt refine_z)
805 {
806   DM_DA *dd = (DM_DA*)da->data;
807 
808   PetscFunctionBegin;
809   PetscValidHeaderSpecific(da,DM_CLASSID,1);
810   PetscValidLogicalCollectiveInt(da,refine_x,2);
811   PetscValidLogicalCollectiveInt(da,refine_y,3);
812   PetscValidLogicalCollectiveInt(da,refine_z,4);
813 
814   if (refine_x > 0) dd->refine_x = refine_x;
815   if (refine_y > 0) dd->refine_y = refine_y;
816   if (refine_z > 0) dd->refine_z = refine_z;
817   PetscFunctionReturn(0);
818 }
819 
820 #undef __FUNCT__
821 #define __FUNCT__ "DMDAGetRefinementFactor"
822 /*@C
823      DMDAGetRefinementFactor - Gets the ratios that the DMDA grid is refined
824 
825     Not Collective
826 
827   Input Parameter:
828 .    da - the DMDA object
829 
830   Output Parameters:
831 +    refine_x - ratio of fine grid to coarse in x direction (2 by default)
832 .    refine_y - ratio of fine grid to coarse in y direction (2 by default)
833 -    refine_z - ratio of fine grid to coarse in z direction (2 by default)
834 
835   Level: intermediate
836 
837     Notes: Pass NULL for values you do not need
838 
839 .seealso: DMRefine(), DMDASetRefinementFactor()
840 @*/
841 PetscErrorCode  DMDAGetRefinementFactor(DM da, PetscInt *refine_x, PetscInt *refine_y,PetscInt *refine_z)
842 {
843   DM_DA *dd = (DM_DA*)da->data;
844 
845   PetscFunctionBegin;
846   PetscValidHeaderSpecific(da,DM_CLASSID,1);
847   if (refine_x) *refine_x = dd->refine_x;
848   if (refine_y) *refine_y = dd->refine_y;
849   if (refine_z) *refine_z = dd->refine_z;
850   PetscFunctionReturn(0);
851 }
852 
853 #undef __FUNCT__
854 #define __FUNCT__ "DMDASetGetMatrix"
855 /*@C
856      DMDASetGetMatrix - Sets the routine used by the DMDA to allocate a matrix.
857 
858     Logically Collective on DMDA
859 
860   Input Parameters:
861 +    da - the DMDA object
862 -    f - the function that allocates the matrix for that specific DMDA
863 
864   Level: developer
865 
866    Notes: See DMDASetBlockFills() that provides a simple way to provide the nonzero structure for
867        the diagonal and off-diagonal blocks of the matrix
868 
869 .seealso: DMCreateMatrix(), DMDASetBlockFills()
870 @*/
871 PetscErrorCode  DMDASetGetMatrix(DM da,PetscErrorCode (*f)(DM, Mat*))
872 {
873   PetscFunctionBegin;
874   PetscValidHeaderSpecific(da,DM_CLASSID,1);
875   da->ops->creatematrix = f;
876   PetscFunctionReturn(0);
877 }
878 
879 #undef __FUNCT__
880 #define __FUNCT__ "DMDARefineOwnershipRanges"
881 /*
882   Creates "balanced" ownership ranges after refinement, constrained by the need for the
883   fine grid boundaries to fall within one stencil width of the coarse partition.
884 
885   Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
886 */
887 static PetscErrorCode DMDARefineOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lc[],PetscInt lf[])
888 {
889   PetscInt       i,totalc = 0,remaining,startc = 0,startf = 0;
890   PetscErrorCode ierr;
891 
892   PetscFunctionBegin;
893   if (ratio < 1) SETERRQ1(PetscObjectComm((PetscObject)da),PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
894   if (ratio == 1) {
895     ierr = PetscMemcpy(lf,lc,m*sizeof(lc[0]));CHKERRQ(ierr);
896     PetscFunctionReturn(0);
897   }
898   for (i=0; i<m; i++) totalc += lc[i];
899   remaining = (!periodic) + ratio * (totalc - (!periodic));
900   for (i=0; i<m; i++) {
901     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
902     if (i == m-1) lf[i] = want;
903     else {
904       const PetscInt nextc = startc + lc[i];
905       /* Move the first fine node of the next subdomain to the right until the coarse node on its left is within one
906        * coarse stencil width of the first coarse node in the next subdomain. */
907       while ((startf+want)/ratio < nextc - stencil_width) want++;
908       /* Move the last fine node in the current subdomain to the left until the coarse node on its right is within one
909        * coarse stencil width of the last coarse node in the current subdomain. */
910       while ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width) want--;
911       /* Make sure all constraints are satisfied */
912       if (want < 0 || want > remaining || ((startf+want)/ratio < nextc - stencil_width)
913           || ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width)) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Could not find a compatible refined ownership range");
914     }
915     lf[i]      = want;
916     startc    += lc[i];
917     startf    += lf[i];
918     remaining -= lf[i];
919   }
920   PetscFunctionReturn(0);
921 }
922 
923 #undef __FUNCT__
924 #define __FUNCT__ "DMDACoarsenOwnershipRanges"
925 /*
926   Creates "balanced" ownership ranges after coarsening, constrained by the need for the
927   fine grid boundaries to fall within one stencil width of the coarse partition.
928 
929   Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
930 */
931 static PetscErrorCode DMDACoarsenOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lf[],PetscInt lc[])
932 {
933   PetscInt       i,totalf,remaining,startc,startf;
934   PetscErrorCode ierr;
935 
936   PetscFunctionBegin;
937   if (ratio < 1) SETERRQ1(PetscObjectComm((PetscObject)da),PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
938   if (ratio == 1) {
939     ierr = PetscMemcpy(lc,lf,m*sizeof(lf[0]));CHKERRQ(ierr);
940     PetscFunctionReturn(0);
941   }
942   for (i=0,totalf=0; i<m; i++) totalf += lf[i];
943   remaining = (!periodic) + (totalf - (!periodic)) / ratio;
944   for (i=0,startc=0,startf=0; i<m; i++) {
945     PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
946     if (i == m-1) lc[i] = want;
947     else {
948       const PetscInt nextf = startf+lf[i];
949       /* Slide first coarse node of next subdomain to the left until the coarse node to the left of the first fine
950        * node is within one stencil width. */
951       while (nextf/ratio < startc+want-stencil_width) want--;
952       /* Slide the last coarse node of the current subdomain to the right until the coarse node to the right of the last
953        * fine node is within one stencil width. */
954       while ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width) want++;
955       if (want < 0 || want > remaining
956           || (nextf/ratio < startc+want-stencil_width) || ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width)) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_SIZ,"Could not find a compatible coarsened ownership range");
957     }
958     lc[i]      = want;
959     startc    += lc[i];
960     startf    += lf[i];
961     remaining -= lc[i];
962   }
963   PetscFunctionReturn(0);
964 }
965 
966 #undef __FUNCT__
967 #define __FUNCT__ "DMRefine_DA"
968 PetscErrorCode  DMRefine_DA(DM da,MPI_Comm comm,DM *daref)
969 {
970   PetscErrorCode ierr;
971   PetscInt       M,N,P,i,dim;
972   DM             da2;
973   DM_DA          *dd = (DM_DA*)da->data,*dd2;
974 
975   PetscFunctionBegin;
976   PetscValidHeaderSpecific(da,DM_CLASSID,1);
977   PetscValidPointer(daref,3);
978 
979   ierr = DMGetDimension(da, &dim);CHKERRQ(ierr);
980   if (dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
981     M = dd->refine_x*dd->M;
982   } else {
983     M = 1 + dd->refine_x*(dd->M - 1);
984   }
985   if (dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
986     if (dim > 1) {
987       N = dd->refine_y*dd->N;
988     } else {
989       N = 1;
990     }
991   } else {
992     N = 1 + dd->refine_y*(dd->N - 1);
993   }
994   if (dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
995     if (dim > 2) {
996       P = dd->refine_z*dd->P;
997     } else {
998       P = 1;
999     }
1000   } else {
1001     P = 1 + dd->refine_z*(dd->P - 1);
1002   }
1003   ierr = DMDACreate(PetscObjectComm((PetscObject)da),&da2);CHKERRQ(ierr);
1004   ierr = DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);CHKERRQ(ierr);
1005   ierr = DMSetDimension(da2,dim);CHKERRQ(ierr);
1006   ierr = DMDASetSizes(da2,M,N,P);CHKERRQ(ierr);
1007   ierr = DMDASetNumProcs(da2,dd->m,dd->n,dd->p);CHKERRQ(ierr);
1008   ierr = DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);CHKERRQ(ierr);
1009   ierr = DMDASetDof(da2,dd->w);CHKERRQ(ierr);
1010   ierr = DMDASetStencilType(da2,dd->stencil_type);CHKERRQ(ierr);
1011   ierr = DMDASetStencilWidth(da2,dd->s);CHKERRQ(ierr);
1012   if (dim == 3) {
1013     PetscInt *lx,*ly,*lz;
1014     ierr = PetscMalloc3(dd->m,&lx,dd->n,&ly,dd->p,&lz);CHKERRQ(ierr);
1015     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1016     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
1017     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);CHKERRQ(ierr);
1018     ierr = DMDASetOwnershipRanges(da2,lx,ly,lz);CHKERRQ(ierr);
1019     ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr);
1020   } else if (dim == 2) {
1021     PetscInt *lx,*ly;
1022     ierr = PetscMalloc2(dd->m,&lx,dd->n,&ly);CHKERRQ(ierr);
1023     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1024     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
1025     ierr = DMDASetOwnershipRanges(da2,lx,ly,NULL);CHKERRQ(ierr);
1026     ierr = PetscFree2(lx,ly);CHKERRQ(ierr);
1027   } else if (dim == 1) {
1028     PetscInt *lx;
1029     ierr = PetscMalloc1(dd->m,&lx);CHKERRQ(ierr);
1030     ierr = DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1031     ierr = DMDASetOwnershipRanges(da2,lx,NULL,NULL);CHKERRQ(ierr);
1032     ierr = PetscFree(lx);CHKERRQ(ierr);
1033   }
1034   dd2 = (DM_DA*)da2->data;
1035 
1036   /* allow overloaded (user replaced) operations to be inherited by refinement clones */
1037   da2->ops->creatematrix = da->ops->creatematrix;
1038   /* da2->ops->createinterpolation = da->ops->createinterpolation; this causes problem with SNESVI */
1039   da2->ops->getcoloring = da->ops->getcoloring;
1040   dd2->interptype       = dd->interptype;
1041 
1042   /* copy fill information if given */
1043   if (dd->dfill) {
1044     ierr = PetscMalloc1(dd->dfill[dd->w]+dd->w+1,&dd2->dfill);CHKERRQ(ierr);
1045     ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
1046   }
1047   if (dd->ofill) {
1048     ierr = PetscMalloc1(dd->ofill[dd->w]+dd->w+1,&dd2->ofill);CHKERRQ(ierr);
1049     ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
1050   }
1051   /* copy the refine information */
1052   dd2->coarsen_x = dd2->refine_x = dd->refine_x;
1053   dd2->coarsen_y = dd2->refine_y = dd->refine_y;
1054   dd2->coarsen_z = dd2->refine_z = dd->refine_z;
1055 
1056   /* copy vector type information */
1057   ierr = DMSetVecType(da2,da->vectype);CHKERRQ(ierr);
1058 
1059   dd2->lf = dd->lf;
1060   dd2->lj = dd->lj;
1061 
1062   da2->leveldown = da->leveldown;
1063   da2->levelup   = da->levelup + 1;
1064 
1065   ierr = DMSetFromOptions(da2);CHKERRQ(ierr);
1066   ierr = DMSetUp(da2);CHKERRQ(ierr);
1067 
1068   /* interpolate coordinates if they are set on the coarse grid */
1069   if (da->coordinates) {
1070     DM  cdaf,cdac;
1071     Vec coordsc,coordsf;
1072     Mat II;
1073 
1074     ierr = DMGetCoordinateDM(da,&cdac);CHKERRQ(ierr);
1075     ierr = DMGetCoordinates(da,&coordsc);CHKERRQ(ierr);
1076     ierr = DMGetCoordinateDM(da2,&cdaf);CHKERRQ(ierr);
1077     /* force creation of the coordinate vector */
1078     ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr);
1079     ierr = DMGetCoordinates(da2,&coordsf);CHKERRQ(ierr);
1080     ierr = DMCreateInterpolation(cdac,cdaf,&II,NULL);CHKERRQ(ierr);
1081     ierr = MatInterpolate(II,coordsc,coordsf);CHKERRQ(ierr);
1082     ierr = MatDestroy(&II);CHKERRQ(ierr);
1083   }
1084 
1085   for (i=0; i<da->bs; i++) {
1086     const char *fieldname;
1087     ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr);
1088     ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr);
1089   }
1090 
1091   *daref = da2;
1092   PetscFunctionReturn(0);
1093 }
1094 
1095 
1096 #undef __FUNCT__
1097 #define __FUNCT__ "DMCoarsen_DA"
1098 PetscErrorCode  DMCoarsen_DA(DM da, MPI_Comm comm,DM *daref)
1099 {
1100   PetscErrorCode ierr;
1101   PetscInt       M,N,P,i,dim;
1102   DM             da2;
1103   DM_DA          *dd = (DM_DA*)da->data,*dd2;
1104 
1105   PetscFunctionBegin;
1106   PetscValidHeaderSpecific(da,DM_CLASSID,1);
1107   PetscValidPointer(daref,3);
1108 
1109   ierr = DMGetDimension(da, &dim);CHKERRQ(ierr);
1110   if (dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1111     M = dd->M / dd->coarsen_x;
1112   } else {
1113     M = 1 + (dd->M - 1) / dd->coarsen_x;
1114   }
1115   if (dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1116     if (dim > 1) {
1117       N = dd->N / dd->coarsen_y;
1118     } else {
1119       N = 1;
1120     }
1121   } else {
1122     N = 1 + (dd->N - 1) / dd->coarsen_y;
1123   }
1124   if (dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0) {
1125     if (dim > 2) {
1126       P = dd->P / dd->coarsen_z;
1127     } else {
1128       P = 1;
1129     }
1130   } else {
1131     P = 1 + (dd->P - 1) / dd->coarsen_z;
1132   }
1133   ierr = DMDACreate(PetscObjectComm((PetscObject)da),&da2);CHKERRQ(ierr);
1134   ierr = DMSetOptionsPrefix(da2,((PetscObject)da)->prefix);CHKERRQ(ierr);
1135   ierr = DMSetDimension(da2,dim);CHKERRQ(ierr);
1136   ierr = DMDASetSizes(da2,M,N,P);CHKERRQ(ierr);
1137   ierr = DMDASetNumProcs(da2,dd->m,dd->n,dd->p);CHKERRQ(ierr);
1138   ierr = DMDASetBoundaryType(da2,dd->bx,dd->by,dd->bz);CHKERRQ(ierr);
1139   ierr = DMDASetDof(da2,dd->w);CHKERRQ(ierr);
1140   ierr = DMDASetStencilType(da2,dd->stencil_type);CHKERRQ(ierr);
1141   ierr = DMDASetStencilWidth(da2,dd->s);CHKERRQ(ierr);
1142   if (dim == 3) {
1143     PetscInt *lx,*ly,*lz;
1144     ierr = PetscMalloc3(dd->m,&lx,dd->n,&ly,dd->p,&lz);CHKERRQ(ierr);
1145     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1146     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
1147     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bz == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_z,dd->p,dd->lz,lz);CHKERRQ(ierr);
1148     ierr = DMDASetOwnershipRanges(da2,lx,ly,lz);CHKERRQ(ierr);
1149     ierr = PetscFree3(lx,ly,lz);CHKERRQ(ierr);
1150   } else if (dim == 2) {
1151     PetscInt *lx,*ly;
1152     ierr = PetscMalloc2(dd->m,&lx,dd->n,&ly);CHKERRQ(ierr);
1153     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1154     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_y,dd->n,dd->ly,ly);CHKERRQ(ierr);
1155     ierr = DMDASetOwnershipRanges(da2,lx,ly,NULL);CHKERRQ(ierr);
1156     ierr = PetscFree2(lx,ly);CHKERRQ(ierr);
1157   } else if (dim == 1) {
1158     PetscInt *lx;
1159     ierr = PetscMalloc1(dd->m,&lx);CHKERRQ(ierr);
1160     ierr = DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DM_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->coarsen_x,dd->m,dd->lx,lx);CHKERRQ(ierr);
1161     ierr = DMDASetOwnershipRanges(da2,lx,NULL,NULL);CHKERRQ(ierr);
1162     ierr = PetscFree(lx);CHKERRQ(ierr);
1163   }
1164   dd2 = (DM_DA*)da2->data;
1165 
1166   /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */
1167   /* da2->ops->createinterpolation = da->ops->createinterpolation; copying this one causes trouble for DMSetVI */
1168   da2->ops->creatematrix = da->ops->creatematrix;
1169   da2->ops->getcoloring  = da->ops->getcoloring;
1170   dd2->interptype        = dd->interptype;
1171 
1172   /* copy fill information if given */
1173   if (dd->dfill) {
1174     ierr = PetscMalloc1(dd->dfill[dd->w]+dd->w+1,&dd2->dfill);CHKERRQ(ierr);
1175     ierr = PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
1176   }
1177   if (dd->ofill) {
1178     ierr = PetscMalloc1(dd->ofill[dd->w]+dd->w+1,&dd2->ofill);CHKERRQ(ierr);
1179     ierr = PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));CHKERRQ(ierr);
1180   }
1181   /* copy the refine information */
1182   dd2->coarsen_x = dd2->refine_x = dd->coarsen_x;
1183   dd2->coarsen_y = dd2->refine_y = dd->coarsen_y;
1184   dd2->coarsen_z = dd2->refine_z = dd->coarsen_z;
1185 
1186   /* copy vector type information */
1187   ierr = DMSetVecType(da2,da->vectype);CHKERRQ(ierr);
1188 
1189   dd2->lf = dd->lf;
1190   dd2->lj = dd->lj;
1191 
1192   da2->leveldown = da->leveldown + 1;
1193   da2->levelup   = da->levelup;
1194 
1195   ierr = DMSetFromOptions(da2);CHKERRQ(ierr);
1196   ierr = DMSetUp(da2);CHKERRQ(ierr);
1197 
1198   /* inject coordinates if they are set on the fine grid */
1199   if (da->coordinates) {
1200     DM         cdaf,cdac;
1201     Vec        coordsc,coordsf;
1202     Mat        inject;
1203     VecScatter vscat;
1204 
1205     ierr = DMGetCoordinateDM(da,&cdaf);CHKERRQ(ierr);
1206     ierr = DMGetCoordinates(da,&coordsf);CHKERRQ(ierr);
1207     ierr = DMGetCoordinateDM(da2,&cdac);CHKERRQ(ierr);
1208     /* force creation of the coordinate vector */
1209     ierr = DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);CHKERRQ(ierr);
1210     ierr = DMGetCoordinates(da2,&coordsc);CHKERRQ(ierr);
1211 
1212     ierr = DMCreateInjection(cdac,cdaf,&inject);CHKERRQ(ierr);
1213     ierr = MatScatterGetVecScatter(inject,&vscat);CHKERRQ(ierr);
1214     ierr = VecScatterBegin(vscat,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1215     ierr = VecScatterEnd(vscat,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
1216     ierr = MatDestroy(&inject);CHKERRQ(ierr);
1217   }
1218 
1219   for (i=0; i<da->bs; i++) {
1220     const char *fieldname;
1221     ierr = DMDAGetFieldName(da,i,&fieldname);CHKERRQ(ierr);
1222     ierr = DMDASetFieldName(da2,i,fieldname);CHKERRQ(ierr);
1223   }
1224 
1225   *daref = da2;
1226   PetscFunctionReturn(0);
1227 }
1228 
1229 #undef __FUNCT__
1230 #define __FUNCT__ "DMRefineHierarchy_DA"
1231 PetscErrorCode  DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[])
1232 {
1233   PetscErrorCode ierr;
1234   PetscInt       i,n,*refx,*refy,*refz;
1235 
1236   PetscFunctionBegin;
1237   PetscValidHeaderSpecific(da,DM_CLASSID,1);
1238   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
1239   if (nlevels == 0) PetscFunctionReturn(0);
1240   PetscValidPointer(daf,3);
1241 
1242   /* Get refinement factors, defaults taken from the coarse DMDA */
1243   ierr = PetscMalloc3(nlevels,&refx,nlevels,&refy,nlevels,&refz);CHKERRQ(ierr);
1244   for (i=0; i<nlevels; i++) {
1245     ierr = DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);CHKERRQ(ierr);
1246   }
1247   n    = nlevels;
1248   ierr = PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,NULL);CHKERRQ(ierr);
1249   n    = nlevels;
1250   ierr = PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,NULL);CHKERRQ(ierr);
1251   n    = nlevels;
1252   ierr = PetscOptionsGetIntArray(((PetscObject)da)->options,((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,NULL);CHKERRQ(ierr);
1253 
1254   ierr = DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]);CHKERRQ(ierr);
1255   ierr = DMRefine(da,PetscObjectComm((PetscObject)da),&daf[0]);CHKERRQ(ierr);
1256   for (i=1; i<nlevels; i++) {
1257     ierr = DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);CHKERRQ(ierr);
1258     ierr = DMRefine(daf[i-1],PetscObjectComm((PetscObject)da),&daf[i]);CHKERRQ(ierr);
1259   }
1260   ierr = PetscFree3(refx,refy,refz);CHKERRQ(ierr);
1261   PetscFunctionReturn(0);
1262 }
1263 
1264 #undef __FUNCT__
1265 #define __FUNCT__ "DMCoarsenHierarchy_DA"
1266 PetscErrorCode  DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[])
1267 {
1268   PetscErrorCode ierr;
1269   PetscInt       i;
1270 
1271   PetscFunctionBegin;
1272   PetscValidHeaderSpecific(da,DM_CLASSID,1);
1273   if (nlevels < 0) SETERRQ(PetscObjectComm((PetscObject)da),PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
1274   if (nlevels == 0) PetscFunctionReturn(0);
1275   PetscValidPointer(dac,3);
1276   ierr = DMCoarsen(da,PetscObjectComm((PetscObject)da),&dac[0]);CHKERRQ(ierr);
1277   for (i=1; i<nlevels; i++) {
1278     ierr = DMCoarsen(dac[i-1],PetscObjectComm((PetscObject)da),&dac[i]);CHKERRQ(ierr);
1279   }
1280   PetscFunctionReturn(0);
1281 }
1282