diff options
author | I.Hawke <schnetter@cct.lsu.edu> | 2006-03-10 13:27:00 +0000 |
---|---|---|
committer | I.Hawke <schnetter@cct.lsu.edu> | 2006-03-10 13:27:00 +0000 |
commit | 1c17048ccb346fc6584340e1d85ef8dc7e47af5e (patch) | |
tree | ac0cc85b668cc8bfadcf750233663d4a6281db74 /Carpet/CarpetLib/src/prolongate_3d_real8_weno.F90 | |
parent | 7f5ff00393f0ae900cbc72695f7f0a972047f228 (diff) |
CarpetLib: Add WENO prolongation
WENO prolongation should be more accurate than ENO prolongation whilst
retaining the monotonicity properties of the ENO operators. The WENO
operators will only work with prolongation_order_space = 5 because of
the stencil width (requires 3 ghost zones).
darcs-hash:20060310132742-34bfa-32c65e7f67cb91ab36dd125a5327f2e16286e807.gz
Diffstat (limited to 'Carpet/CarpetLib/src/prolongate_3d_real8_weno.F90')
-rw-r--r-- | Carpet/CarpetLib/src/prolongate_3d_real8_weno.F90 | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/Carpet/CarpetLib/src/prolongate_3d_real8_weno.F90 b/Carpet/CarpetLib/src/prolongate_3d_real8_weno.F90 new file mode 100644 index 000000000..5e8ad6a8c --- /dev/null +++ b/Carpet/CarpetLib/src/prolongate_3d_real8_weno.F90 @@ -0,0 +1,378 @@ +!!$ -*-Fortran-*- + +#include "cctk.h" + + +!!$ This routine performs "WENO" prolongation. It is intended to be used +!!$ with GFs that are not expected to be smooth, particularly those +!!$ that must also obey certain constraints. The obvious example is the +!!$ density in hydrodynamics, which may be discontinuous yet must be +!!$ strictly positive. +!!$ +!!$ To ensure that this prolongation method is used you should add the +!!$ tag +!!$ +!!$ tags='Prolongation="WENO"' +!!$ +!!$ to the interface.ccl on the appropriate group. +!!$ +!!$ This applies WENO2 type limiting to the slope, checking over the +!!$ entire coarse grid cell for the least oscillatory quadratic in each +!!$ direction. If the slope changes sign over the extrema, linear +!!$ interpolation is used instead. +!!$ +!!$ The actual weno1d function is defined in the routine +!!$ +!!$ prolongate_3d_real8_weno.F77 + + +#define CHKIDX(i,j,k, imax,jmax,kmax, where) \ +if ((i).lt.1 .or. (i).gt.(imax) \ + .or. (j).lt.1 .or. (j).gt.(jmax) \ + .or. (k).lt.1 .or. (k).gt.(kmax)) then &&\ + write (msg, '(a, " array index out of bounds: shape is (",i4,",",i4,",",i4,"), index is (",i4,",",i4,",",i4,")")') \ + (where), (imax), (jmax), (kmax), (i), (j), (k) &&\ + call CCTK_WARN (0, msg(1:len_trim(msg))) &&\ +end if + +function weno1d(q) + + implicit none + + CCTK_REAL8 :: weno1d + CCTK_REAL8 :: q(5) + CCTK_REAL8 :: zero, one, two, three, four, five, eight, ten, eleven, & + thirteen, fifteen, nineteen, twentyfive, thirtyone, epsilon + parameter (zero = 0) + parameter (one = 1) + parameter (two = 2) + parameter (three = 3) + parameter (four = 4) + parameter (five = 5) + parameter (eight = 8) + parameter (ten = 10) + parameter (eleven = 11) + parameter (thirteen = 13) + parameter (fifteen = 15) + parameter (nineteen = 19) + parameter (twentyfive = 25) + parameter (thirtyone = 31) + parameter (epsilon = 0.000000001) + + CCTK_REAL8, dimension(0:2,0:2) :: c + CCTK_REAL8 :: wtildesum, qmax, qmin + CCTK_REAL8, dimension(0:2) :: d, beta, wtilde, w, vr + logical, dimension(0:2) :: hacked + + integer :: j, k + +!!$ Linear weights + + d(0) = three / ten + d(1) = three / five + d(2) = one / ten + + c(0,0) = three / eight + c(0,1) = three / four + c(0,2) = -one / eight + c(1,0) = -one / eight + c(1,1) = three / four + c(1,2) = three / eight + c(2,0) = three / eight + c(2,1) = -five / four + c(2,2) = fifteen / eight + +!!$ Substencils + + do j = 0, 2 + vr(j) = 0.d0 + do k = 0, 2 + vr(j) = vr(j) + c(j, k) * q(3 - j + k) + end do + end do + +!!$ Nonlinear weights + + beta(0) = (ten * q(3)**2 - & + thirtyone * q(3) * q(4) + & + twentyfive * q(4)**2 + & + eleven * q(3) * q(5) - & + nineteen * q(4) * q(5) + & + four * q(5)**2) / three + beta(1) = (four * q(2)**2 - & + thirteen * q(2) * q(3) + & + thirteen * q(3)**2 + & + five * q(2) * q(4) - & + thirteen * q(3) * q(4) + & + four * q(4)**2) / three + beta(2) = (four * q(1)**2 - & + nineteen * q(1) * q(2) + & + twentyfive * q(2)**2 + & + eleven * q(1) * q(3) - & + thirtyone * q(2) * q(3) + & + ten * q(3)**2) / three + + do j = 0, 2 + wtilde(j) = d(j) / (epsilon + beta(j))**2 + end do + +!!$ Hack the weights if outside the range + + qmax = maxval(q) + qmin = minval(q) + + do j = 0, 2 + hacked(j) = .false. + if ( (qmax - vr(j)) * (vr(j) - qmin) < 0.d0 ) then + wtilde(j) = 0.d0 + hacked(j) = .true. + end if + end do + +!!$ If all weights were hacked we cannot get a good interpolant; +!!$ drop to linear interpolation + + if (hacked(0).and.hacked(1).and.hacked(2)) then + +!!$ Linear interpolation + weno1d = 0.5d0 * (q(3) + q(4)) + + else + + wtildesum = wtilde(0) + wtilde(1) + wtilde(2) + w = wtilde / wtildesum + + weno1d = 0.d0 + + do j = 0, 2 + weno1d = weno1d + w(j) * vr(j) + end do + + end if + +!!$ if (.not.( (weno1d .ge. 0.d0 ).or.(weno1d .le. 0.d0) ) ) then +!!$ write(*,*) 'Error?', weno1d +!!$ write(*,*) 'Done weno1d', weno1d, hacked +!!$ write(*,*) 'Substencil',vr +!!$ write(*,*) 'Weights', w +!!$ write(*,*) 'Indicators', beta +!!$ write(*,*) 'Input', q +!!$ end if + +!!$ write(*,*) 'Done weno1d', weno1d, hacked +!!$ write(*,*) 'Substencil',vr +!!$ write(*,*) 'Weights', w +!!$ write(*,*) 'Indicators', beta +!!$ write(*,*) 'Input', q + +end function weno1d + +subroutine prolongate_3d_real8_weno (src, srciext, srcjext, & + srckext, dst, dstiext, dstjext, dstkext, srcbbox, & + dstbbox, regbbox) + + implicit none + + CCTK_REAL8 one + parameter (one = 1) + + integer srciext, srcjext, srckext + CCTK_REAL8 src(srciext,srcjext,srckext) + integer dstiext, dstjext, dstkext + CCTK_REAL8 dst(dstiext,dstjext,dstkext) +!!$ bbox(:,1) is lower boundary (inclusive) +!!$ bbox(:,2) is upper boundary (inclusive) +!!$ bbox(:,3) is stride + integer srcbbox(3,3), dstbbox(3,3), regbbox(3,3) + + integer offsetlo, offsethi + + integer regiext, regjext, regkext + + integer dstifac, dstjfac, dstkfac + + integer srcioff, srcjoff, srckoff + integer dstioff, dstjoff, dstkoff + + integer i, j, k + integer i0, j0, k0 + integer fi, fj, fk + integer ii, jj, kk + integer d + + CCTK_REAL8, dimension(0:4,0:4) :: tmp1 + CCTK_REAL8, dimension(0:4) :: tmp2 + + external weno1d + CCTK_REAL8 weno1d + + CCTK_REAL8 half, zero + parameter (half = 0.5) + parameter (zero = 0) + + do d=1,3 + if (srcbbox(d,3).eq.0 .or. dstbbox(d,3).eq.0 & + .or. regbbox(d,3).eq.0) then + call CCTK_WARN (0, "Internal error: stride is zero") + end if + if (srcbbox(d,3).le.regbbox(d,3) & + .or. dstbbox(d,3).ne.regbbox(d,3)) then + call CCTK_WARN (0, "Internal error: strides disagree") + end if + if (mod(srcbbox(d,3), dstbbox(d,3)).ne.0) then + call CCTK_WARN (0, "Internal error: destination strides are not integer multiples of the source strides") + end if + if (mod(srcbbox(d,1), srcbbox(d,3)).ne.0 & + .or. mod(dstbbox(d,1), dstbbox(d,3)).ne.0 & + .or. mod(regbbox(d,1), regbbox(d,3)).ne.0) then + call CCTK_WARN (0, "Internal error: array origins are not integer multiples of the strides") + end if + if (regbbox(d,1).gt.regbbox(d,2)) then +!!$ This could be handled, but is likely to point to an error elsewhere + call CCTK_WARN (0, "Internal error: region extent is empty") + end if + regkext = (regbbox(d,2) - regbbox(d,1)) / regbbox(d,3) + 1 + dstkfac = srcbbox(d,3) / dstbbox(d,3) + srckoff = (regbbox(d,1) - srcbbox(d,1)) / dstbbox(d,3) + offsetlo = regbbox(d,3) + if (mod(srckoff + 0, dstkfac).eq.0) then + offsetlo = 0 + if (regkext.gt.1) then + offsetlo = regbbox(d,3) + end if + end if + offsethi = regbbox(d,3) + if (mod(srckoff + regkext-1, dstkfac).eq.0) then + offsethi = 0 + if (regkext.gt.1) then + offsethi = regbbox(d,3) + end if + end if + if (regbbox(d,1)-offsetlo.lt.srcbbox(d,1) & + .or. regbbox(d,2)+offsethi.gt.srcbbox(d,2) & + .or. regbbox(d,1).lt.dstbbox(d,1) & + .or. regbbox(d,2).gt.dstbbox(d,2)) then + call CCTK_WARN (0, "Internal error: region extent is not contained in array extent") + end if + end do + + if (srciext.ne.(srcbbox(1,2)-srcbbox(1,1))/srcbbox(1,3)+1 & + .or. srcjext.ne.(srcbbox(2,2)-srcbbox(2,1))/srcbbox(2,3)+1 & + .or. srckext.ne.(srcbbox(3,2)-srcbbox(3,1))/srcbbox(3,3)+1 & + .or. dstiext.ne.(dstbbox(1,2)-dstbbox(1,1))/dstbbox(1,3)+1 & + .or. dstjext.ne.(dstbbox(2,2)-dstbbox(2,1))/dstbbox(2,3)+1 & + .or. dstkext.ne.(dstbbox(3,2)-dstbbox(3,1))/dstbbox(3,3)+1) then + call CCTK_WARN (0, "Internal error: array sizes don't agree with bounding boxes") + end if + + regiext = (regbbox(1,2) - regbbox(1,1)) / regbbox(1,3) + 1 + regjext = (regbbox(2,2) - regbbox(2,1)) / regbbox(2,3) + 1 + regkext = (regbbox(3,2) - regbbox(3,1)) / regbbox(3,3) + 1 + + dstifac = srcbbox(1,3) / dstbbox(1,3) + dstjfac = srcbbox(2,3) / dstbbox(2,3) + dstkfac = srcbbox(3,3) / dstbbox(3,3) + + srcioff = (regbbox(1,1) - srcbbox(1,1)) / dstbbox(1,3) + srcjoff = (regbbox(2,1) - srcbbox(2,1)) / dstbbox(2,3) + srckoff = (regbbox(3,1) - srcbbox(3,1)) / dstbbox(3,3) + + dstioff = (regbbox(1,1) - dstbbox(1,1)) / dstbbox(1,3) + dstjoff = (regbbox(2,1) - dstbbox(2,1)) / dstbbox(2,3) + dstkoff = (regbbox(3,1) - dstbbox(3,1)) / dstbbox(3,3) + +!!$ Loop over fine region + + do k = 0, regkext-1 + k0 = (srckoff + k) / dstkfac + fk = mod(srckoff + k, dstkfac) + + do j = 0, regjext-1 + j0 = (srcjoff + j) / dstjfac + fj = mod(srcjoff + j, dstjfac) + + do i = 0, regiext-1 + i0 = (srcioff + i) / dstifac + fi = mod(srcioff + i, dstifac) + +!!$ Where is the fine grid point w.r.t the coarse grid? + + select case (fi + 10*fj + 100*fk) + case (0) +!!$ On a coarse grid point exactly! + + dst (dstioff+i+1, dstjoff+j+1, dstkoff+k+1) = & + src(i0+1,j0+1,k0+1) + + case (1) +!!$ Interpolate only in x + + dst (dstioff+i+1, dstjoff+j+1, dstkoff+k+1) = & + weno1d(src(i0-1:i0+3,j0+1,k0+1)) + + case (10) +!!$ Interpolate only in y + + dst (dstioff+i+1, dstjoff+j+1, dstkoff+k+1) = & + weno1d(src(i0+1,j0-1:j0+3,k0+1)) + + case (11) +!!$ Interpolate only in x and y + + do jj = 0, 4 + tmp2(jj) = weno1d(src(i0-1:i0+3,j0+jj-1,k0+1)) + end do + + dst (dstioff+i+1, dstjoff+j+1, dstkoff+k+1) = & + weno1d(tmp2(0:4)) + + case (100) +!!$ Interpolate only in z + + dst (dstioff+i+1, dstjoff+j+1, dstkoff+k+1) = & + weno1d(src(i0+1,j0+1,k0-1:k0+3)) + + case (101) +!!$ Interpolate only in x and z + + do kk = 0, 4 + tmp2(kk) = weno1d(src(i0-1:i0+3,j0+1,k0+kk-1)) + end do + + dst (dstioff+i+1, dstjoff+j+1, dstkoff+k+1) = & + weno1d(tmp2(0:4)) + + case (110) +!!$ Interpolate only in y and z + + do kk = 0, 4 + tmp2(kk) = weno1d(src(i0+1,j0-1:j0+3,k0+kk-1)) + end do + + dst (dstioff+i+1, dstjoff+j+1, dstkoff+k+1) = & + weno1d(tmp2(0:4)) + + case (111) +!!$ Interpolate in all of x, y, and z + + do jj = 0, 4 + do kk = 0, 4 + tmp1(jj,kk) = weno1d(src(i0-1:i0+3,j0+jj-1,k0+kk-1)) + end do + end do + do ii = 0, 4 + tmp2(ii) = weno1d(tmp1(0:4,ii)) + end do + + dst (dstioff+i+1, dstjoff+j+1, dstkoff+k+1) = & + weno1d(tmp2(0:4)) + + case default + call CCTK_WARN(0, "Internal error in WENO prolongation. Should only be used with refinement factor 2!") + end select + + end do + end do + end do + +end subroutine prolongate_3d_real8_weno |