FE-Project
Loading...
Searching...
No Matches
scale_fast_fourier_transform.F90
Go to the documentation of this file.
1!-------------------------------------------------------------------------------
2!> Module common / FFT
3!!
4!! @par Description
5!! A module to provide a fast Fourier transformation
6!!
7!! @author Yuta Kawai, Team SCALE
8!!
9!! @par Reference
10!! - Cooleyand & Tukey, 1965:
11!! An algorithm for the machine calculation of complex Fourier series
12!! Mathematics of Computation, 19, 297-301
13!! - Bluestein 1970:
14!! A linear filtering approach to the computation of discrete Fourier transform
15!! IEEE Transactions on Audio and Electroacoustics, 18(4), 451-455.
16!<
17#include "scaleFElib.h"
19 !-----------------------------------------------------------------------------
20 !
21 !++ used modules
22 !
23 use scale_precision
24 use scale_io
25 use scale_prc
26 use scale_const, only: &
27 undef8 => const_undef8, &
28 pi => const_pi
29
30 !-----------------------------------------------------------------------------
31 implicit none
32 private
33
34 !-----------------------------------------------------------------------------
35 !
36 !++ Public type & procedure
37 !
38 type, public :: fastfouriertransform1d
39 integer :: n
40 integer :: m
41 complex(RP), allocatable :: w_forward(:)
42 complex(RP), allocatable :: w_backward(:)
43
44 ! for N /= 2^n
45 logical :: use_bluestein
46 complex(RP), allocatable :: w1_bluestein(:)
47 complex(RP), allocatable :: w2_bluestein(:)
48
49 contains
50 procedure :: init => fastfouriertransform1d_init
51 procedure :: final => fastfouriertransform1d_final
52 procedure :: forward_cmplx => fastfouriertransform1d_forward_cmplx
53 procedure :: forward_real => fastfouriertransform1d_forward_real
54 generic :: forward => forward_cmplx, forward_real
55 procedure :: backward => fastfouriertransform1d_backward
57
58 !-----------------------------------------------------------------------------
59 !
60 !++ Public parameters & variables
61 !
62 !-----------------------------------------------------------------------------
63 !
64 !++ Private procedure
65 !
66 !-----------------------------------------------------------------------------
67 !
68 !++ Private parameters & variables
69 !
70
71 !-----------------------------------------------------------------------------
72contains
73!OCL SERIAL
74 subroutine fastfouriertransform1d_init( this, N )
75 implicit none
76 class(fastfouriertransform1d), intent(inout) :: this
77 integer, intent(in) :: N
78
79 complex(RP) :: JJ
80 integer :: k
81
82 real(RP) :: angle0
83 real(RP) :: angle
84
85 integer :: M
86 integer :: MM
87
88 complex(RP) :: w1, w2
89 !-----------------------------------
90
91 jj = cmplx( 0.0_rp, 1.0_rp )
92
93 this%N = n
94 if ( is_power_of_two(n) ) then
95 this%use_bluestein = .false.
96 mm = n / 2
97 log_info("FastFourierTransform1D_Init",*) "use_bluestein=F"
98 log_info("FastFourierTransform1D_Init",*) "MM=", mm
99 else
100 this%use_bluestein = .true.
101 m = 1
102 do while ( m < 2*n-1 )
103 m = m * 2
104 end do
105 mm = m / 2
106 log_info("FastFourierTransform1D_Init",*) "use_bluestein=T"
107 log_info("FastFourierTransform1D_Init",*) "M=", m, "MM=", mm
108 end if
109 this%M = m
110
111 allocate( this%W_forward(mm), this%W_backward(mm) )
112
113 angle0 = 2.0_rp * pi / real(2*mm, kind=rp)
114 !$omp parallel do private(angle)
115 do k=0, mm-1
116 angle = angle0 * real(k, kind=rp)
117 this%W_forward (k+1) = exp(- jj * angle )
118 this%W_backward(k+1) = exp( jj * angle )
119 end do
120
121 if ( this%use_bluestein ) then
122 allocate( this%W1_bluestein(n), this%W2_bluestein(n) )
123 !$omp parallel do private(angle)
124 do k=0, n-1
125 angle = pi * real(k*k,kind=rp) / real(n, kind=rp)
126 this%W1_bluestein(k+1) = exp(- jj * angle )
127 this%W2_bluestein(k+1) = exp( jj * angle )
128 end do
129 end if
130
131 return
132 end subroutine fastfouriertransform1d_init
133
134!OCL SERIAL
135 subroutine fastfouriertransform1d_forward_real( this, q, s )
136 implicit none
137 class(fastfouriertransform1d), intent(in) :: this
138 real(RP), intent(in) :: q(this%N)
139 complex(RP), intent(out) :: s(this%N)
140
141 complex(RP) :: q_(this%N)
142 integer :: i
143 !-----------------------------------
144
145 do i=1, this%N
146 q_(i) = cmplx(q(i), 0.0_rp, kind=rp)
147 end do
148 call this%Forward_cmplx( q_, s )
149 return
150 end subroutine fastfouriertransform1d_forward_real
151
152!OCL SERIAL
153 subroutine fastfouriertransform1d_forward_cmplx( this, q, s )
154 implicit none
155 class(fastfouriertransform1d), intent(in) :: this
156 complex(RP), intent(in) :: q(this%N)
157 complex(RP), intent(out) :: s(this%N)
158
159 integer :: i
160 real(RP) :: scaling
161 !-----------------------------------
162
163 if ( this%use_bluestein ) then
164 call fft1d_bluestein( s, &
165 q, this%W_forward, this%W_backward, this%W1_bluestein, this%W2_bluestein, &
166 this%N, this%M )
167 else
168 call fft1d_norecursive_core( s, &
169 q, this%W_forward, this%N )
170 ! call fft1d_recursive_core( s, &
171 ! q, this%W_forward, this%N, this%N )
172 end if
173
174 scaling = 1.0_rp / real( this%N )
175 s(:) = scaling * s(:)
176 return
177 end subroutine fastfouriertransform1d_forward_cmplx
178
179!OCL SERIAL
180 subroutine fastfouriertransform1d_backward( this, s, q )
181 implicit none
182 class(fastfouriertransform1d), intent(in) :: this
183 complex(RP), intent(in) :: s(this%N)
184 real(RP), intent(out) :: q(this%N)
185
186 complex(RP) :: q_(this%N)
187 integer :: i
188 !-----------------------------------
189
190 if ( this%use_bluestein ) then
191 call fft1d_bluestein( q_, &
192 s, this%W_forward, this%W_backward, this%W2_bluestein, this%W1_bluestein, &
193 this%N, this%M )
194 else
195 call fft1d_norecursive_core( q_, &
196 s, this%W_backward, this%N )
197 end if
198
199 do i=1, this%N
200 q(i) = real(q_(i), kind=rp)
201 end do
202 return
203 end subroutine fastfouriertransform1d_backward
204
205!OCL SERIAL
206 subroutine fastfouriertransform1d_final( this )
207 implicit none
208 class(fastfouriertransform1d), intent(inout) :: this
209 !-----------------------------------
210
211 deallocate( this%W_forward, this%W_backward)
212
213 if ( this%use_bluestein ) then
214 deallocate( this%W1_bluestein, this%W2_bluestein )
215 end if
216 return
217 end subroutine fastfouriertransform1d_final
218
219!- private -------------
220!OCL SERIAL
221 subroutine fft1d_bluestein( x_out, x_in, W_forward, W_backward, W1, W2, N, M )
222 implicit none
223 integer, intent(in) :: N, M
224 complex(RP), intent(out) :: x_out(N)
225 complex(RP), intent(in) :: x_in(N)
226 complex(RP), intent(in) :: W_forward(M/2) !< twiddle factor for forward transformation
227 complex(RP), intent(in) :: W_backward(M/2) !< twiddle factor for backward transformation
228 complex(RP), intent(in) :: W1(N)
229 complex(RP), intent(in) :: W2(N)
230
231 complex(RP) :: a(M), b(M)
232 complex(RP) :: AA(M), BB(M), CC(M)
233 integer :: i
234 real(RP) :: scaling
235 !---------------------------
236
237 !- Chirp pre-processing
238 a(:) = 0.0_rp
239 b(:) = 0.0_rp
240 do i=0, n-1
241 a(i+1) = x_in(i+1) * w1(i+1)
242 b(i+1) = w2(i+1)
243 end do
244 ! Fill symmetric part of b
245 do i=1, n-1
246 b(m-i+1) = w2(i+1)
247 end do
248
249 !- Convolution C = A * B
250
251 call fft1d_norecursive_core( aa, &
252 a, w_forward, m )
253 call fft1d_norecursive_core( bb, &
254 b, w_forward, m )
255
256 call fft1d_norecursive_core( cc, &
257 aa(:) * bb(:), w_backward, m )
258
259 !- Chirp post-processing
260 scaling = 1.0_rp / real( m )
261 do i=1, n
262 x_out(i) = scaling * cc(i) * w1(i)
263 end do
264 return
265 end subroutine fft1d_bluestein
266
267!OCL SERIAL
268 subroutine fft1d_norecursive_core( x_out, x_in, W, N )
269 implicit none
270 integer, intent(in) :: N
271 complex(RP), intent(out) :: x_out(N)
272 complex(RP), intent(in) :: x_in(N)
273 complex(RP), intent(in) :: W(N/2) !< twiddle factor
274
275 integer :: rev
276 integer :: nbits
277 complex(RP) :: tmp(N)
278
279 integer :: i, j
280 integer :: k
281 integer :: m
282 integer :: ind
283
284 integer :: stage
285 integer :: step
286
287 integer :: s
288 complex(RP) :: t, u
289 !---------------------------
290
291 !- bit-reversal permutation
292 tmp(:) = x_in(:)
293
294 nbits = int( log(real(n,kind=rp)) / log(2.0_rp) + 0.5_rp )
295 do i=0, n-1
296 rev = 0
297 do j=0, nbits-1
298 if ( i/2**j - 2*(i/2**(j+1)) == 1 ) rev = rev + 2**(nbits-j-1)
299 end do
300 x_out(rev+1) = tmp(i+1)
301 end do
302
303 !- Iterative butterfly using W
304 m = 1
305 do stage=1, nbits
306 step = 2*m
307 s = n / step
308 do k=0, n-1, step
309 do j=0, m-1
310 ind = j*s
311 t = w(ind+1) * x_out(k+j+m+1)
312 u = x_out(k+j+1)
313 x_out(k+j+1 ) = u + t
314 x_out(k+j+1+m) = u - t
315 end do
316 end do
317 m = step
318 end do
319 return
320 end subroutine fft1d_norecursive_core
321
322!OCL SERIAL
323 recursive subroutine fft1d_recursive_core( x_out, x_in, W, N, N0 )
324 implicit none
325 integer, intent(in) :: N
326 integer, intent(in) :: N0
327 complex(RP), intent(out) :: x_out(N)
328 complex(RP), intent(in) :: x_in(N)
329 complex(RP), intent(in) :: W(N0/2) !< twiddle factor
330
331 complex(RP) :: even(N/2), odd(N/2)
332 complex(RP) :: E(N/2), O(N/2)
333
334 integer :: k
335 integer :: s
336 complex(RP) :: twiddle
337 !---------------------------
338
339 if ( n==1 ) then
340 x_out(1) = x_in(1)
341 return
342 end if
343
344 even(:) = x_in(1:n:2)
345 odd(:) = x_in(2:n:2)
346
347 call fft1d_recursive_core( e, &
348 even, w, n/2, n0 )
349 call fft1d_recursive_core( o, &
350 odd, w, n/2, n0 )
351
352 s = n0 / n
353 do k=0, n/2-1
354 x_out(k+1 ) = e(k+1) + w(s*k+1) * o(k+1)
355 x_out(k+1+n/2) = e(k+1) - w(s*k+1) * o(k+1)
356 end do
357 return
358 end subroutine fft1d_recursive_core
359
360!OCL SERIAL
361 logical function is_power_of_two(N)
362 implicit none
363 integer, intent(in) :: N
364 !--------------
365 is_power_of_two = (n > 0) .and. (iand(n, n-1) == 0)
366 return
367 end function is_power_of_two