Actual source code: da.c
1: #include <private/daimpl.h> /*I "petscdmda.h" I*/
6: /*@
7: DMDASetDim - Sets the dimension
9: Collective on DMDA
11: Input Parameters:
12: + da - the DMDA
13: - dim - the dimension (or PETSC_DECIDE)
15: Level: intermediate
17: .seealso: DaGetDim(), DMDASetSizes()
18: @*/
19: PetscErrorCode DMDASetDim(DM da, PetscInt dim)
20: {
21: DM_DA *dd = (DM_DA*)da->data;
25: if (dd->dim > 0 && dim != dd->dim) SETERRQ2(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot change DMDA dim from %D after it was set to %D",dd->dim,dim);
26: dd->dim = dim;
27: return(0);
28: }
32: /*@
33: DMDASetSizes - Sets the global sizes
35: Logically Collective on DMDA
37: Input Parameters:
38: + da - the DMDA
39: . M - the global X size (or PETSC_DECIDE)
40: . N - the global Y size (or PETSC_DECIDE)
41: - P - the global Z size (or PETSC_DECIDE)
43: Level: intermediate
45: .seealso: DMDAGetSize(), PetscSplitOwnership()
46: @*/
47: PetscErrorCode DMDASetSizes(DM da, PetscInt M, PetscInt N, PetscInt P)
48: {
49: DM_DA *dd = (DM_DA*)da->data;
57: dd->M = M;
58: dd->N = N;
59: dd->P = P;
60: return(0);
61: }
65: /*@
66: DMDASetNumProcs - Sets the number of processes in each dimension
68: Logically Collective on DMDA
70: Input Parameters:
71: + da - the DMDA
72: . m - the number of X procs (or PETSC_DECIDE)
73: . n - the number of Y procs (or PETSC_DECIDE)
74: - p - the number of Z procs (or PETSC_DECIDE)
76: Level: intermediate
78: .seealso: DMDASetSizes(), DMDAGetSize(), PetscSplitOwnership()
79: @*/
80: PetscErrorCode DMDASetNumProcs(DM da, PetscInt m, PetscInt n, PetscInt p)
81: {
82: DM_DA *dd = (DM_DA*)da->data;
89: dd->m = m;
90: dd->n = n;
91: dd->p = p;
92: return(0);
93: }
97: /*@
98: DMDASetBoundaryType - Sets the type of ghost nodes on domain boundaries.
100: Not collective
102: Input Parameter:
103: + da - The DMDA
104: - bx,by,bz - One of DMDA_BOUNDARY_NONE, DMDA_BOUNDARY_GHOSTED, DMDA_BOUNDARY_PERIODIC
106: Level: intermediate
108: .keywords: distributed array, periodicity
109: .seealso: DMDACreate(), DMDestroy(), DMDA, DMDABoundaryType
110: @*/
111: PetscErrorCode DMDASetBoundaryType(DM da,DMDABoundaryType bx,DMDABoundaryType by,DMDABoundaryType bz)
112: {
113: DM_DA *dd = (DM_DA*)da->data;
120: dd->bx = bx;
121: dd->by = by;
122: dd->bz = bz;
123: return(0);
124: }
128: /*@
129: DMDASetDof - Sets the number of degrees of freedom per vertex
131: Not collective
133: Input Parameter:
134: + da - The DMDA
135: - dof - Number of degrees of freedom
137: Level: intermediate
139: .keywords: distributed array, degrees of freedom
140: .seealso: DMDACreate(), DMDestroy(), DMDA
141: @*/
142: PetscErrorCode DMDASetDof(DM da, PetscInt dof)
143: {
144: DM_DA *dd = (DM_DA*)da->data;
149: dd->w = dof;
150: da->bs = dof;
151: return(0);
152: }
156: /*@
157: DMDASetStencilType - Sets the type of the communication stencil
159: Logically Collective on DMDA
161: Input Parameter:
162: + da - The DMDA
163: - stype - The stencil type, use either DMDA_STENCIL_BOX or DMDA_STENCIL_STAR.
165: Level: intermediate
167: .keywords: distributed array, stencil
168: .seealso: DMDACreate(), DMDestroy(), DMDA
169: @*/
170: PetscErrorCode DMDASetStencilType(DM da, DMDAStencilType stype)
171: {
172: DM_DA *dd = (DM_DA*)da->data;
177: dd->stencil_type = stype;
178: return(0);
179: }
183: /*@
184: DMDASetStencilWidth - Sets the width of the communication stencil
186: Logically Collective on DMDA
188: Input Parameter:
189: + da - The DMDA
190: - width - The stencil width
192: Level: intermediate
194: .keywords: distributed array, stencil
195: .seealso: DMDACreate(), DMDestroy(), DMDA
196: @*/
197: PetscErrorCode DMDASetStencilWidth(DM da, PetscInt width)
198: {
199: DM_DA *dd = (DM_DA*)da->data;
204: dd->s = width;
205: return(0);
206: }
210: static PetscErrorCode DMDACheckOwnershipRanges_Private(DM da,PetscInt M,PetscInt m,const PetscInt lx[])
211: {
212: PetscInt i,sum;
215: if (M < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Global dimension not set");
216: for (i=sum=0; i<m; i++) sum += lx[i];
217: if (sum != M) SETERRQ2(((PetscObject)da)->comm,PETSC_ERR_ARG_INCOMP,"Ownership ranges sum to %D but global dimension is %D",sum,M);
218: return(0);
219: }
223: /*@
224: DMDASetOwnershipRanges - Sets the number of nodes in each direction on each process
226: Logically Collective on DMDA
228: Input Parameter:
229: + da - The DMDA
230: . lx - array containing number of nodes in the X direction on each process, or PETSC_NULL. If non-null, must be of length da->m
231: . ly - array containing number of nodes in the Y direction on each process, or PETSC_NULL. If non-null, must be of length da->n
232: - lz - array containing number of nodes in the Z direction on each process, or PETSC_NULL. If non-null, must be of length da->p.
234: Level: intermediate
236: .keywords: distributed array
237: .seealso: DMDACreate(), DMDestroy(), DMDA
238: @*/
239: PetscErrorCode DMDASetOwnershipRanges(DM da, const PetscInt lx[], const PetscInt ly[], const PetscInt lz[])
240: {
242: DM_DA *dd = (DM_DA*)da->data;
243:
246: if (lx) {
247: if (dd->m < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
248: DMDACheckOwnershipRanges_Private(da,dd->M,dd->m,lx);
249: if (!dd->lx) {
250: PetscMalloc(dd->m*sizeof(PetscInt), &dd->lx);
251: }
252: PetscMemcpy(dd->lx, lx, dd->m*sizeof(PetscInt));
253: }
254: if (ly) {
255: if (dd->n < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
256: DMDACheckOwnershipRanges_Private(da,dd->N,dd->n,ly);
257: if (!dd->ly) {
258: PetscMalloc(dd->n*sizeof(PetscInt), &dd->ly);
259: }
260: PetscMemcpy(dd->ly, ly, dd->n*sizeof(PetscInt));
261: }
262: if (lz) {
263: if (dd->p < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set ownership ranges before setting number of procs");
264: DMDACheckOwnershipRanges_Private(da,dd->P,dd->p,lz);
265: if (!dd->lz) {
266: PetscMalloc(dd->p*sizeof(PetscInt), &dd->lz);
267: }
268: PetscMemcpy(dd->lz, lz, dd->p*sizeof(PetscInt));
269: }
270: return(0);
271: }
275: /*@
276: DMDASetInterpolationType - Sets the type of interpolation that will be
277: returned by DMGetInterpolation()
279: Logically Collective on DMDA
281: Input Parameter:
282: + da - initial distributed array
283: . ctype - DMDA_Q1 and DMDA_Q0 are currently the only supported forms
285: Level: intermediate
287: Notes: you should call this on the coarser of the two DMDAs you pass to DMGetInterpolation()
289: .keywords: distributed array, interpolation
291: .seealso: DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), DMDestroy(), DMDA, DMDAInterpolationType
292: @*/
293: PetscErrorCode DMDASetInterpolationType(DM da,DMDAInterpolationType ctype)
294: {
295: DM_DA *dd = (DM_DA*)da->data;
300: dd->interptype = ctype;
301: return(0);
302: }
306: /*@
307: DMDAGetInterpolationType - Gets the type of interpolation that will be
308: used by DMGetInterpolation()
310: Not Collective
312: Input Parameter:
313: . da - distributed array
315: Output Parameter:
316: . ctype - interpolation type (DMDA_Q1 and DMDA_Q0 are currently the only supported forms)
318: Level: intermediate
320: .keywords: distributed array, interpolation
322: .seealso: DMDA, DMDAInterpolationType, DMDASetInterpolationType(), DMGetInterpolation()
323: @*/
324: PetscErrorCode DMDAGetInterpolationType(DM da,DMDAInterpolationType *ctype)
325: {
326: DM_DA *dd = (DM_DA*)da->data;
331: *ctype = dd->interptype;
332: return(0);
333: }
337: /*@C
338: DMDAGetNeighbors - Gets an array containing the MPI rank of all the current
339: processes neighbors.
341: Not Collective
343: Input Parameter:
344: . da - the DMDA object
346: Output Parameters:
347: . ranks - the neighbors ranks, stored with the x index increasing most rapidly.
348: this process itself is in the list
350: Notes: In 2d the array is of length 9, in 3d of length 27
351: Not supported in 1d
352: Do not free the array, it is freed when the DMDA is destroyed.
354: Fortran Notes: In fortran you must pass in an array of the appropriate length.
356: Level: intermediate
358: @*/
359: PetscErrorCode DMDAGetNeighbors(DM da,const PetscMPIInt *ranks[])
360: {
361: DM_DA *dd = (DM_DA*)da->data;
364: *ranks = dd->neighbors;
365: return(0);
366: }
370: /*@C
371: DMDAGetOwnershipRanges - Gets the ranges of indices in the x, y and z direction that are owned by each process
373: Not Collective
375: Input Parameter:
376: . da - the DMDA object
378: Output Parameter:
379: + lx - ownership along x direction (optional)
380: . ly - ownership along y direction (optional)
381: - lz - ownership along z direction (optional)
383: Level: intermediate
385: Note: these correspond to the optional final arguments passed to DMDACreate(), DMDACreate2d(), DMDACreate3d()
387: In Fortran one must pass in arrays lx, ly, and lz that are long enough to hold the values; the sixth, seventh and
388: eighth arguments from DMDAGetInfo()
390: In C you should not free these arrays, nor change the values in them. They will only have valid values while the
391: DMDA they came from still exists (has not been destroyed).
393: .seealso: DMDAGetCorners(), DMDAGetGhostCorners(), DMDACreate(), DMDACreate1d(), DMDACreate2d(), DMDACreate3d(), VecGetOwnershipRanges()
394: @*/
395: PetscErrorCode DMDAGetOwnershipRanges(DM da,const PetscInt *lx[],const PetscInt *ly[],const PetscInt *lz[])
396: {
397: DM_DA *dd = (DM_DA*)da->data;
401: if (lx) *lx = dd->lx;
402: if (ly) *ly = dd->ly;
403: if (lz) *lz = dd->lz;
404: return(0);
405: }
409: /*@
410: DMDASetRefinementFactor - Set the ratios that the DMDA grid is refined
412: Logically Collective on DMDA
414: Input Parameters:
415: + da - the DMDA object
416: . refine_x - ratio of fine grid to coarse in x direction (2 by default)
417: . refine_y - ratio of fine grid to coarse in y direction (2 by default)
418: - refine_z - ratio of fine grid to coarse in z direction (2 by default)
420: Options Database:
421: + -da_refine_x - refinement ratio in x direction
422: . -da_refine_y - refinement ratio in y direction
423: - -da_refine_z - refinement ratio in z direction
425: Level: intermediate
427: Notes: Pass PETSC_IGNORE to leave a value unchanged
429: .seealso: DMRefine(), DMDAGetRefinementFactor()
430: @*/
431: PetscErrorCode DMDASetRefinementFactor(DM da, PetscInt refine_x, PetscInt refine_y,PetscInt refine_z)
432: {
433: DM_DA *dd = (DM_DA*)da->data;
441: if (refine_x > 0) dd->refine_x = refine_x;
442: if (refine_y > 0) dd->refine_y = refine_y;
443: if (refine_z > 0) dd->refine_z = refine_z;
444: return(0);
445: }
449: /*@C
450: DMDAGetRefinementFactor - Gets the ratios that the DMDA grid is refined
452: Not Collective
454: Input Parameter:
455: . da - the DMDA object
457: Output Parameters:
458: + refine_x - ratio of fine grid to coarse in x direction (2 by default)
459: . refine_y - ratio of fine grid to coarse in y direction (2 by default)
460: - refine_z - ratio of fine grid to coarse in z direction (2 by default)
462: Level: intermediate
464: Notes: Pass PETSC_NULL for values you do not need
466: .seealso: DMRefine(), DMDASetRefinementFactor()
467: @*/
468: PetscErrorCode DMDAGetRefinementFactor(DM da, PetscInt *refine_x, PetscInt *refine_y,PetscInt *refine_z)
469: {
470: DM_DA *dd = (DM_DA*)da->data;
474: if (refine_x) *refine_x = dd->refine_x;
475: if (refine_y) *refine_y = dd->refine_y;
476: if (refine_z) *refine_z = dd->refine_z;
477: return(0);
478: }
482: /*@C
483: DMDASetGetMatrix - Sets the routine used by the DMDA to allocate a matrix.
485: Logically Collective on DMDA
487: Input Parameters:
488: + da - the DMDA object
489: - f - the function that allocates the matrix for that specific DMDA
491: Level: developer
493: Notes: See DMDASetBlockFills() that provides a simple way to provide the nonzero structure for
494: the diagonal and off-diagonal blocks of the matrix
496: .seealso: DMGetMatrix(), DMDASetBlockFills()
497: @*/
498: PetscErrorCode DMDASetGetMatrix(DM da,PetscErrorCode (*f)(DM, const MatType,Mat*))
499: {
502: da->ops->getmatrix = f;
503: return(0);
504: }
508: /*
509: Creates "balanced" ownership ranges after refinement, constrained by the need for the
510: fine grid boundaries to fall within one stencil width of the coarse partition.
512: Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
513: */
514: static PetscErrorCode DMDARefineOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lc[],PetscInt lf[])
515: {
516: PetscInt i,totalc = 0,remaining,startc = 0,startf = 0;
520: if (ratio < 1) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
521: if (ratio == 1) {
522: PetscMemcpy(lf,lc,m*sizeof(lc[0]));
523: return(0);
524: }
525: for (i=0; i<m; i++) totalc += lc[i];
526: remaining = (!periodic) + ratio * (totalc - (!periodic));
527: for (i=0; i<m; i++) {
528: PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
529: if (i == m-1) lf[i] = want;
530: else {
531: const PetscInt nextc = startc + lc[i];
532: /* Move the first fine node of the next subdomain to the right until the coarse node on its left is within one
533: * coarse stencil width of the first coarse node in the next subdomain. */
534: while ((startf+want)/ratio < nextc - stencil_width) want++;
535: /* Move the last fine node in the current subdomain to the left until the coarse node on its right is within one
536: * coarse stencil width of the last coarse node in the current subdomain. */
537: while ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width) want--;
538: /* Make sure all constraints are satisfied */
539: if (want < 0 || want > remaining
540: || ((startf+want)/ratio < nextc - stencil_width)
541: || ((startf+want-1+ratio-1)/ratio > nextc-1+stencil_width))
542: SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_SIZ,"Could not find a compatible refined ownership range");
543: }
544: lf[i] = want;
545: startc += lc[i];
546: startf += lf[i];
547: remaining -= lf[i];
548: }
549: return(0);
550: }
554: /*
555: Creates "balanced" ownership ranges after coarsening, constrained by the need for the
556: fine grid boundaries to fall within one stencil width of the coarse partition.
558: Uses a greedy algorithm to handle non-ideal layouts, could probably do something better.
559: */
560: static PetscErrorCode DMDACoarsenOwnershipRanges(DM da,PetscBool periodic,PetscInt stencil_width,PetscInt ratio,PetscInt m,const PetscInt lf[],PetscInt lc[])
561: {
562: PetscInt i,totalf,remaining,startc,startf;
566: if (ratio < 1) SETERRQ1(((PetscObject)da)->comm,PETSC_ERR_USER,"Requested refinement ratio %D must be at least 1",ratio);
567: if (ratio == 1) {
568: PetscMemcpy(lc,lf,m*sizeof(lf[0]));
569: return(0);
570: }
571: for (i=0,totalf=0; i<m; i++) totalf += lf[i];
572: remaining = (!periodic) + (totalf - (!periodic)) / ratio;
573: for (i=0,startc=0,startf=0; i<m; i++) {
574: PetscInt want = remaining/(m-i) + !!(remaining%(m-i));
575: if (i == m-1) lc[i] = want;
576: else {
577: const PetscInt nextf = startf+lf[i];
578: /* Slide first coarse node of next subdomain to the left until the coarse node to the left of the first fine
579: * node is within one stencil width. */
580: while (nextf/ratio < startc+want-stencil_width) want--;
581: /* Slide the last coarse node of the current subdomain to the right until the coarse node to the right of the last
582: * fine node is within one stencil width. */
583: while ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width) want++;
584: if (want < 0 || want > remaining
585: || (nextf/ratio < startc+want-stencil_width)
586: || ((nextf-1+ratio-1)/ratio > startc+want-1+stencil_width))
587: SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_SIZ,"Could not find a compatible coarsened ownership range");
588: }
589: lc[i] = want;
590: startc += lc[i];
591: startf += lf[i];
592: remaining -= lc[i];
593: }
594: return(0);
595: }
599: PetscErrorCode DMRefine_DA(DM da,MPI_Comm comm,DM *daref)
600: {
602: PetscInt M,N,P;
603: DM da2;
604: DM_DA *dd = (DM_DA*)da->data,*dd2;
610: if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
611: M = dd->refine_x*dd->M;
612: } else {
613: M = 1 + dd->refine_x*(dd->M - 1);
614: }
615: if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
616: N = dd->refine_y*dd->N;
617: } else {
618: N = 1 + dd->refine_y*(dd->N - 1);
619: }
620: if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
621: P = dd->refine_z*dd->P;
622: } else {
623: P = 1 + dd->refine_z*(dd->P - 1);
624: }
625: if (dd->dim == 3) {
626: PetscInt *lx,*ly,*lz;
627: PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);
628: DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
629: DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
630: DMDARefineOwnershipRanges(da,(PetscBool)(dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);
631: DMDACreate3d(((PetscObject)da)->comm,dd->bx,dd->by,dd->bz,dd->stencil_type,M,N,P,dd->m,dd->n,dd->p,dd->w,dd->s,lx,ly,lz,&da2);
632: PetscFree3(lx,ly,lz);
633: } else if (dd->dim == 2) {
634: PetscInt *lx,*ly;
635: PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);
636: DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
637: DMDARefineOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
638: DMDACreate2d(((PetscObject)da)->comm,dd->bx,dd->by,dd->stencil_type,M,N,dd->m,dd->n,dd->w,dd->s,lx,ly,&da2);
639: PetscFree2(lx,ly);
640: } else if (dd->dim == 1) {
641: PetscInt *lx;
642: PetscMalloc(dd->m*sizeof(PetscInt),&lx);
643: DMDARefineOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
644: DMDACreate1d(((PetscObject)da)->comm,dd->bx,M,dd->w,dd->s,lx,&da2);
645: PetscFree(lx);
646: }
647: dd2 = (DM_DA*)da2->data;
649: /* allow overloaded (user replaced) operations to be inherited by refinement clones */
650: da2->ops->getmatrix = da->ops->getmatrix;
651: /* da2->ops->getinterpolation = da->ops->getinterpolation; this causes problem with SNESVI */
652: da2->ops->getcoloring = da->ops->getcoloring;
653: dd2->interptype = dd->interptype;
654:
655: /* copy fill information if given */
656: if (dd->dfill) {
657: PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);
658: PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));
659: }
660: if (dd->ofill) {
661: PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);
662: PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));
663: }
664: /* copy the refine information */
665: dd2->refine_x = dd->refine_x;
666: dd2->refine_y = dd->refine_y;
667: dd2->refine_z = dd->refine_z;
669: /* copy vector type information */
670: PetscFree(da2->vectype);
671: PetscStrallocpy(da->vectype,&da2->vectype);
673: dd2->lf = dd->lf;
674: dd2->lj = dd->lj;
676: /* interpolate coordinates if they are set on the coarse grid */
677: if (dd->coordinates) {
678: DM cdaf,cdac;
679: Vec coordsc,coordsf;
680: Mat II;
681:
682: DMDAGetCoordinateDA(da,&cdac);
683: DMDAGetCoordinates(da,&coordsc);
684: DMDAGetCoordinateDA(da2,&cdaf);
685: /* force creation of the coordinate vector */
686: DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);
687: DMDAGetCoordinates(da2,&coordsf);
688: DMGetInterpolation(cdac,cdaf,&II,PETSC_NULL);
689: MatInterpolate(II,coordsc,coordsf);
690: MatDestroy(&II);
691: }
692: *daref = da2;
693: return(0);
694: }
698: PetscErrorCode DMCoarsen_DA(DM da, MPI_Comm comm,DM *daref)
699: {
701: PetscInt M,N,P;
702: DM da2;
703: DM_DA *dd = (DM_DA*)da->data,*dd2;
709: if (dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
710: M = dd->M / dd->refine_x;
711: } else {
712: M = 1 + (dd->M - 1) / dd->refine_x;
713: }
714: if (dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
715: N = dd->N / dd->refine_y;
716: } else {
717: N = 1 + (dd->N - 1) / dd->refine_y;
718: }
719: if (dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0){
720: P = dd->P / dd->refine_z;
721: } else {
722: P = 1 + (dd->P - 1) / dd->refine_z;
723: }
724: if (dd->dim == 3) {
725: PetscInt *lx,*ly,*lz;
726: PetscMalloc3(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly,dd->p,PetscInt,&lz);
727: DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
728: DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
729: DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bz == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_z,dd->p,dd->lz,lz);
730: DMDACreate3d(((PetscObject)da)->comm,dd->bx,dd->by,dd->bz,dd->stencil_type,M,N,P,dd->m,dd->n,dd->p,dd->w,dd->s,lx,ly,lz,&da2);
731: PetscFree3(lx,ly,lz);
732: } else if (dd->dim == 2) {
733: PetscInt *lx,*ly;
734: PetscMalloc2(dd->m,PetscInt,&lx,dd->n,PetscInt,&ly);
735: DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
736: DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->by == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_y,dd->n,dd->ly,ly);
737: DMDACreate2d(((PetscObject)da)->comm,dd->bx,dd->by,dd->stencil_type,M,N,dd->m,dd->n,dd->w,dd->s,lx,ly,&da2);
738: PetscFree2(lx,ly);
739: } else if (dd->dim == 1) {
740: PetscInt *lx;
741: PetscMalloc(dd->m*sizeof(PetscInt),&lx);
742: DMDACoarsenOwnershipRanges(da,(PetscBool)(dd->bx == DMDA_BOUNDARY_PERIODIC || dd->interptype == DMDA_Q0),dd->s,dd->refine_x,dd->m,dd->lx,lx);
743: DMDACreate1d(((PetscObject)da)->comm,dd->bx,M,dd->w,dd->s,lx,&da2);
744: PetscFree(lx);
745: }
746: dd2 = (DM_DA*)da2->data;
748: /* allow overloaded (user replaced) operations to be inherited by refinement clones; why are only some inherited and not all? */
749: /* da2->ops->getinterpolation = da->ops->getinterpolation; copying this one causes trouble for DMSetVI */
750: da2->ops->getmatrix = da->ops->getmatrix;
751: da2->ops->getcoloring = da->ops->getcoloring;
752: dd2->interptype = dd->interptype;
753:
754: /* copy fill information if given */
755: if (dd->dfill) {
756: PetscMalloc((dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->dfill);
757: PetscMemcpy(dd2->dfill,dd->dfill,(dd->dfill[dd->w]+dd->w+1)*sizeof(PetscInt));
758: }
759: if (dd->ofill) {
760: PetscMalloc((dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt),&dd2->ofill);
761: PetscMemcpy(dd2->ofill,dd->ofill,(dd->ofill[dd->w]+dd->w+1)*sizeof(PetscInt));
762: }
763: /* copy the refine information */
764: dd2->refine_x = dd->refine_x;
765: dd2->refine_y = dd->refine_y;
766: dd2->refine_z = dd->refine_z;
768: /* copy vector type information */
769: PetscFree(da2->vectype);
770: PetscStrallocpy(da->vectype,&da2->vectype);
772: dd2->lf = dd->lf;
773: dd2->lj = dd->lj;
775: /* inject coordinates if they are set on the fine grid */
776: if (dd->coordinates) {
777: DM cdaf,cdac;
778: Vec coordsc,coordsf;
779: VecScatter inject;
780:
781: DMDAGetCoordinateDA(da,&cdaf);
782: DMDAGetCoordinates(da,&coordsf);
783: DMDAGetCoordinateDA(da2,&cdac);
784: /* force creation of the coordinate vector */
785: DMDASetUniformCoordinates(da2,0.0,1.0,0.0,1.0,0.0,1.0);
786: DMDAGetCoordinates(da2,&coordsc);
787:
788: DMGetInjection(cdac,cdaf,&inject);
789: VecScatterBegin(inject,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);
790: VecScatterEnd(inject ,coordsf,coordsc,INSERT_VALUES,SCATTER_FORWARD);
791: VecScatterDestroy(&inject);
792: }
793: *daref = da2;
794: return(0);
795: }
799: PetscErrorCode DMRefineHierarchy_DA(DM da,PetscInt nlevels,DM daf[])
800: {
802: PetscInt i,n,*refx,*refy,*refz;
806: if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
807: if (nlevels == 0) return(0);
810: /* Get refinement factors, defaults taken from the coarse DMDA */
811: PetscMalloc3(nlevels,PetscInt,&refx,nlevels,PetscInt,&refy,nlevels,PetscInt,&refz);
812: for (i=0; i<nlevels; i++) {
813: DMDAGetRefinementFactor(da,&refx[i],&refy[i],&refz[i]);
814: }
815: n = nlevels;
816: PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_x",refx,&n,PETSC_NULL);
817: n = nlevels;
818: PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_y",refy,&n,PETSC_NULL);
819: n = nlevels;
820: PetscOptionsGetIntArray(((PetscObject)da)->prefix,"-da_refine_hierarchy_z",refz,&n,PETSC_NULL);
822: DMDASetRefinementFactor(da,refx[0],refy[0],refz[0]);
823: DMRefine(da,((PetscObject)da)->comm,&daf[0]);
824: for (i=1; i<nlevels; i++) {
825: DMDASetRefinementFactor(daf[i-1],refx[i],refy[i],refz[i]);
826: DMRefine(daf[i-1],((PetscObject)da)->comm,&daf[i]);
827: }
828: PetscFree3(refx,refy,refz);
829: return(0);
830: }
834: PetscErrorCode DMCoarsenHierarchy_DA(DM da,PetscInt nlevels,DM dac[])
835: {
837: PetscInt i;
841: if (nlevels < 0) SETERRQ(((PetscObject)da)->comm,PETSC_ERR_ARG_OUTOFRANGE,"nlevels cannot be negative");
842: if (nlevels == 0) return(0);
844: DMCoarsen(da,((PetscObject)da)->comm,&dac[0]);
845: for (i=1; i<nlevels; i++) {
846: DMCoarsen(dac[i-1],((PetscObject)da)->comm,&dac[i]);
847: }
848: return(0);
849: }