dns-hit3d-fdm/m_filter_xfftw.f90
2014-04-25 18:54:58 +09:00

289 lines
8.1 KiB
Fortran

!======================================================================
! Module that contains filtering rocedure for the part of the code that
! addvects lagrangian particles
!
! Time-stamp: <2009-05-20 11:50:52 (chumakov)>
!======================================================================
module m_filter_xfftw
use m_parameters
use x_fftw
use m_work
implicit none
! filter type (Gaussian by default)
integer :: filter_type = 2
! filter size
real*8 :: filter_size
! filter function in Fourier space
real*8, allocatable :: filter_g(:,:,:)
!======================================================================
contains
!======================================================================
!======================================================================
! filering subroutine for 2*pi^3-periodic domain
! IN: ss(n,:,:,:)
! OUT: ss(n:,;,:)
!======================================================================
subroutine filter_xfftw(n)
use m_io
implicit none
integer n
integer :: ix, iy, iz
real*8 :: a,b,c,d
!----------------------------------------------------------------------
!!$ call xFFT3d(1,n)
! multiplying wrk(:,:,:,n) by filter_g
! remember both are in the complex form
do iy = 1, nz
do iz = 1, nz_all
do ix = 1, nx + 1, 2
a = wrk(ix,iz,iy,n)
b = wrk(ix+1,iz,iy,n)
c = filter_g(ix,iz,iy)
d = filter_g(ix+1,iz,iy)
wrk(ix , iz, iy, n) = a*c - b*d
wrk(ix + 1, iz, iy, n) = b*c + a*d
end do
end do
end do
!!$ ! perform inverse FFT
!!$ call xFFT3d(-1,n)
return
end subroutine filter_xfftw
!======================================================================
! filering subroutine for 2*pi^3-periodic domain
! IN: ss(n,:,:,:)
! OUT: ss(n:,;,:)
!======================================================================
subroutine filter_xfftw_fields(n)
use m_io
use m_fields
implicit none
integer n
integer :: ix, iy, iz
real*8 :: a,b,c,d
!----------------------------------------------------------------------
!!$ call xFFT3d(1,n)
! multiplying wrk(:,:,:,n) by filter_g
! remember both are in the complex form
do iy = 1, nz
do iz = 1, nz_all
do ix = 1, nx + 1, 2
a = fields(ix,iz,iy,n)
b = fields(ix+1,iz,iy,n)
c = filter_g(ix,iz,iy)
d = filter_g(ix+1,iz,iy)
fields(ix , iz, iy, n) = a*c - b*d
fields(ix + 1, iz, iy, n) = b*c + a*d
end do
end do
end do
!!$ ! perform inverse FFT
!!$ call xFFT3d(-1,n)
return
end subroutine filter_xfftw_fields
!======================================================================
!======================================================================
!======================================================================
! subroutine that initializes the filter function filter_g
! IN: filter_type - type of the filter
! delta - filter's characteristic width
!
! OUT: filter_g - normalized FFT of the filter function
!======================================================================
subroutine filter_xfftw_init
use m_parameters
use m_io
use m_work
implicit none
real*8 delta
integer :: di,dj,dk,i,j,k, m
integer :: idelta,sum1
integer :: ii(8)
real*8 :: rx,ry,rz
real*8 :: const1,const2
filter_size = particles_filter_size
delta = filter_size
if (task.eq.'hydro') delta = dx*four
if (delta .lt. dx*three) then
write(out,*) "filter_xfftw_init: delta is too small:",delta,dx
write(out,*) "Must be at least 3*dx = ",three*dx
call flush(out)
call my_exit(-1)
end if
write(out,"('initializing the filter, filter_size = ',2e15.6)") delta, dx
call flush(out)
! the main idea is as follows:
! 1) create the filter kernel in one of the fields array
! 2) transform it into the Fourier space
! 3) put it into the array filter_g
! number of the slice in the fields array that will be used
m = LBOUND(fields,4)
!---------------------------------------------------------------
! define the filtering function
!---------------------------------------------------------------
case_filter_type: select case (filter_type)
!-------------------------------------------------------------------
! tophat filter
!-------------------------------------------------------------------
case (1)
write(out,*) '-- tophat filter, delta =',delta
write(out,*) "Tophat filter is not working at the moment."
write(out,*) "We're sorry for the inconvenience, stopping."
call my_exit(-1)
fields(:,:,:,m) = zip
idelta = delta / dx / 2
! normalization constant
const1 = real((2*idelta+1)**3,8)
const2 = 1.0d0 / const1
do k = 1,nz
dk = min(myid*nz+k-1,nz*numprocs-(myid*nz+k)+1)
do j = 1,ny
dj = min(j-1,ny-j+1)
do i = 1,nx
di = min(i-1,nx-i+1)
fields(i,j,k,m) = zip
if (di.le.idelta .and. dj.le.idelta .and. dk.le.idelta) then
fields(i,j,k,m) = const2
end if
end do
end do
end do
!-------------------------------------------------------------------
! Gaussian filter
!-------------------------------------------------------------------
case (2)
write(out,*) '-- Gaussian filter, delta =',delta
call flush(out)
fields(:,:,:,m) = zip
const1 = 6.0d0 / delta**2
const2 = sqrt(const1/PI)**3 *dx**3
do k = 1,nz
dk = min(myid*nz+k-1,nz*numprocs-(myid*nz+k)+1)
rz = dx * real(dk,8)
do j = 1,ny
dj = min(j-1,ny-j+1)
ry = dx * real(dj,8)
do i = 1,nx
di = min(i-1,nx-i+1)
rx = dx * real(di,8)
rx = rx*rx+ry*ry+rz*rz
fields(i,j,k,m) = const2*exp(-const1*rx)
if (fields(i,j,k,m) < 1.e-20) fields(i,j,k,m) = zip
end do
end do
end do
!-------------------------------------------------------------------
! linear filter
!-------------------------------------------------------------------
case(3)
write(out,*) '-- linear filter, delta =',delta
! if(myid.eq.0) print*,'-- linear filter, delta =',delta
const1 = 24.0d0 / (PI*delta**3) *dx**3
const2 = delta**2 / 4.0d0
do k = 1,nz
dk = min(myid*nz+k-1,nz*numprocs-(myid*nz+k)+1)
rz = dx * real(dk,8)
do j = 1,ny
dj = min(j-1,ny-j+1)
ry = dx * real(dj,8)
do i = 1,nx
di = min(i-1,nx-i+1)
rx = dx * real(di,8)
rx = rx*rx+ry*ry+rz*rz
fields(i,j,k,m) = zip
if (rx.le.const2) fields(i,j,k,m) = &
const1*(1.0d0-2.0d0*sqrt(rx)/delta)
end do
end do
end do
case default
print *,'FILTER_FFT_INIT: wrong filter_type:',filter_type
stop
end select case_filter_type
! outputting the sum of all elements of G.
! It should equal 1.0.
const1 = sum(fields(1:nx,1:ny,1:nz,m))
call MPI_REDUCE(const1,const2,1,MPI_REAL8,MPI_SUM,0,MPI_COMM_TASK,mpi_err)
if(myid.eq.0) write(out,*) '-- NORM OF G: ',const2
! compute FFT of g
call xFFT3d_fields(1,m)
! putting the FFT of the filter into filter_g.
! allocating the filter array
if (.not.allocated(filter_g)) then
allocate(filter_g(nx+2,ny,nz), stat=ierr)
if (ierr /= 0) stop 'cannot allocate filter_g'
filter_g = zip
write(out,*) 'allocated filter_g'
call flush(out)
end if
filter_g(:,:,:) = fields(:,:,:,m)
!!$! no need to normalize filter_g because our implementation of FFT
!!$! normalizes the result anyways
!!$ const1 = one/real(nx**3,8)
!!$ do k=1,nz
!!$ do j=1,ny
!!$ do i=1,nx+2
!!$ filter_g(i,j,k) = wrk(i,j,k,m)*const1
!!$ end do
!!$ end do
!!$ end do
return
end subroutine filter_xfftw_init
end module m_filter_xfftw