Skip to content

Commit ef304e4

Browse files
committed
Add easy-to-use interface: fft & ifft for complex sequences.
1 parent 6d7ab85 commit ef304e4

File tree

7 files changed

+268
-2
lines changed

7 files changed

+268
-2
lines changed

doc/specs/fftpack.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,98 @@ program demo_zfftb
196196
call zfftb(4,x,w) !! `x` returns [(4.0,0.0), (8.0,0.0), (12.0,0.0), (16.0,0.0)].
197197
end program demo_zfftb
198198
```
199+
200+
## `fft`
201+
202+
### Description
203+
204+
Computes the forward complex discrete fourier
205+
transform (the fourier analysis).
206+
207+
### Status
208+
209+
Experimental.
210+
211+
### Class
212+
213+
Pure function.
214+
215+
### Snytax
216+
217+
`call [[fftpack(module):fft(interface)]](x [, n])`
218+
219+
### Argument
220+
221+
`x`: Shall be a `complex` array.
222+
This argument is `intent(in)`.
223+
224+
`n`: Shall be an `integer` scalar.
225+
This argument is `intent(in)` and `optional`.
226+
The needed length of the `complex` sequence `c`.
227+
228+
#### Warning
229+
230+
if `n <= size(x)`, the first `n` elements of `x` will be included in the calculation.
231+
232+
if `n > size(x)`, the all elements of `x` and `n-size(x)` elements filled with zeros will be included in the calculation.
233+
234+
### Example
235+
236+
```fortran
237+
program demo_fft
238+
use fftpack, only: fft
239+
complex(kind=8) :: x(4)
240+
x = [real(kind=8) :: 1.0, 2.0, 3.0, 4.0]
241+
print *, fft(x) !! [(10.0,0.0), (-2.0,2.0), (-2.0,0.0), (-2.0,-2.0)].
242+
print *, fft(x,3) !! [(6.0,0.0), (-1.5,0.86), (-1.5,0.86)].
243+
print *, fft(x,5) !! [(10.0,0.0), (-4.0,1.3), (1.5,-2.1), (1.5,2.1), (-4.0,1.3)].
244+
end program demo_fft
245+
```
246+
247+
## `ifft`
248+
249+
### Description
250+
251+
Unnormalized inverse of `fft`.
252+
253+
### Status
254+
255+
Experimental.
256+
257+
### Class
258+
259+
Pure function.
260+
261+
### Snytax
262+
263+
`call [[fftpack(module):ifft(interface)]](x [, n])`
264+
265+
### Argument
266+
267+
`x`: Shall be a `complex` array.
268+
This argument is `intent(in)`.
269+
270+
`n`: Shall be an `integer` scalar.
271+
This argument is `intent(in)` and `optional`.
272+
The needed length of the `complex` sequence `c`.
273+
274+
#### Warning
275+
276+
if `n <= size(x)`, the first `n` elements of `x` will be included in the calculation.
277+
278+
if `n > size(x)`, the all elements of `x` and `n-size(x)` elements filled with zeros will be included in the calculation.
279+
280+
### Example
281+
282+
```fortran
283+
program demo_ifft
284+
use fftpack, only: fft, ifft
285+
complex(kind=8) :: x(4)
286+
x = [real(kind=8) :: 1.0, 2.0, 3.0, 4.0]
287+
print *, fft(x) !! [(10.0,0.0), (-2.0,2.0), (-2.0,0.0), (-2.0,-2.0)].
288+
print *, fft(x,3) !! [(6.0,0.0), (-1.5,0.86), (-1.5,0.86)].
289+
print *, fft(x,5) !! [(10.0,0.0), (-4.0,1.3), (1.5,-2.1), (1.5,2.1), (-4.0,1.3)].
290+
print *, ifft(fft(x))/4.0 !! [(1.0,0.0), (2.0,0.0), (3.0,0.0), (4.0,0.0)]
291+
print *, ifft(fft(x), 3) !! [(6.0,2.0), (10.3,-1.0), (13.73,-1.0)]
292+
end program demo_ifft
293+
```

fpm.toml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,14 @@ main = "tstfft.f"
2323
[[test]]
2424
name = "fftpack_zfft"
2525
source-dir = "test"
26-
main = "test_fftpack_zfft.f90"
26+
main = "test_fftpack_zfft.f90"
27+
28+
[[test]]
29+
name = "fftpack_fft"
30+
source-dir = "test"
31+
main = "test_fftpack_fft.f90"
32+
33+
[[test]]
34+
name = "fftpack_ifft"
35+
source-dir = "test"
36+
main = "test_fftpack_ifft.f90"

src/fftpack.f90

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module fftpack
55
private
66

77
public :: zffti, zfftf, zfftb
8+
public :: fft, ifft
89

910
interface
1011

@@ -42,4 +43,28 @@ end subroutine zfftb
4243

4344
end interface
4445

45-
end module fftpack
46+
!> Version: experimental
47+
!>
48+
!> Forward transform of a double complex periodic sequence.
49+
!> ([Specifiction](../page/specs/fftpack.html#fft))
50+
interface fft
51+
pure module function fft_cdp(x, n) result(result)
52+
complex(kind=dp), intent(in) :: x(:)
53+
integer, intent(in), optional :: n
54+
complex(kind=dp), allocatable :: result(:)
55+
end function fft_cdp
56+
end interface fft
57+
58+
!> Version: experimental
59+
!>
60+
!> Backward transform of a double complex periodic sequence.
61+
!> ([Specifiction](../page/specs/fftpack.html#ifft))
62+
interface ifft
63+
pure module function ifft_cdp(x, n) result(result)
64+
complex(kind=dp), intent(in) :: x(:)
65+
integer, intent(in), optional :: n
66+
complex(kind=dp), allocatable :: result(:)
67+
end function ifft_cdp
68+
end interface ifft
69+
70+
end module fftpack

src/fftpack_fft.f90

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
submodule(fftpack) fftpack_fft
2+
3+
contains
4+
5+
!> Forward transform of a double complex periodic sequence.
6+
pure module function fft_cdp(x, n) result(result)
7+
complex(kind=dp), intent(in) :: x(:)
8+
integer, intent(in), optional :: n
9+
complex(kind=dp), allocatable :: result(:)
10+
11+
integer :: lenseq, lensav, lenwrk
12+
real(kind=dp), allocatable :: wsave(:)
13+
14+
if (present(n)) then
15+
lenseq = n
16+
if (lenseq <= size(x)) then
17+
result = x(:lenseq)
18+
else if (lenseq > size(x)) then
19+
result = [x, ((0.0_dp, 0.0_dp), i=1, lenseq - size(x))]
20+
end if
21+
else
22+
lenseq = size(x)
23+
result = x
24+
end if
25+
26+
!> Initialize FFT
27+
lensav = 4*lenseq + 15
28+
allocate (wsave(lensav))
29+
call zffti(lenseq, wsave)
30+
31+
!> Forward transformation
32+
call zfftf(lenseq, result, wsave)
33+
34+
end function fft_cdp
35+
36+
end submodule fftpack_fft

src/fftpack_ifft.f90

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
submodule(fftpack) fftpack_ifft
2+
3+
contains
4+
5+
!> Backward transform of a double complex periodic sequence.
6+
pure module function ifft_cdp(x, n) result(result)
7+
complex(kind=dp), intent(in) :: x(:)
8+
integer, intent(in), optional :: n
9+
complex(kind=dp), allocatable :: result(:)
10+
11+
integer :: lenseq, lensav, lenwrk
12+
real(kind=dp), allocatable :: wsave(:)
13+
14+
if (present(n)) then
15+
lenseq = n
16+
if (lenseq <= size(x)) then
17+
result = x(:lenseq)
18+
else if (lenseq > size(x)) then
19+
result = [x, ((0.0_dp, 0.0_dp), i=1, lenseq - size(x))]
20+
end if
21+
else
22+
lenseq = size(x)
23+
result = x
24+
end if
25+
26+
!> Initialize FFT
27+
lensav = 4*lenseq + 15
28+
allocate (wsave(lensav))
29+
call zffti(lenseq, wsave)
30+
31+
!> Backward transformation
32+
call zfftb(lenseq, result, wsave)
33+
34+
end function ifft_cdp
35+
36+
end submodule fftpack_ifft

test/test_fftpack_fft.f90

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
program tester
2+
3+
call test_fftpack_fft()
4+
print *, "All tests in `test_fftpack_fft` passed."
5+
6+
contains
7+
8+
subroutine check(condition, msg)
9+
logical, intent(in) :: condition
10+
character(*), intent(in) :: msg
11+
if (.not. condition) error stop msg
12+
end subroutine check
13+
14+
subroutine test_fftpack_fft
15+
use fftpack, only: fft
16+
use iso_fortran_env, only: dp => real64
17+
real(kind=dp) :: eps = 1.0e-10
18+
19+
complex(kind=dp) :: x(3)
20+
21+
x = [real(kind=dp) :: 1.0, 2.0, 3.0]
22+
23+
call check(sum(abs(fft(x, 2) - [complex(kind=dp) ::(3.0, 0.0), (-1.0, 0.0)])) < eps, &
24+
msg="sum(abs(fft(x,2) - [complex(kind=dp) ::(3.0, 0.0), (-1.0, 0.0)])) < eps failed.")
25+
call check(sum(abs(fft(x, 3) - fft(x))) < eps, &
26+
msg="sum(abs(fft(x,3) - fft(3))) < eps failed.")
27+
call check(sum(abs(fft(x, 4) - [complex(kind=dp) ::(6.0, 0.0), (-2.0, -2.0), (2.0, 0.0), (-2.0, 2.0)])) < eps, &
28+
msg="sum(abs(fft(x,4) - [complex(kind=dp) ::(6.0, 0.0), (-2.0, -2.0), (2.0,0.0), (-2.0,2.0)])) < eps failed.")
29+
30+
end subroutine test_fftpack_fft
31+
32+
end program tester

test/test_fftpack_ifft.f90

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
program tester
2+
3+
call test_fftpack_ifft()
4+
print *, "All tests in `test_fftpack_fft` passed."
5+
6+
contains
7+
8+
subroutine check(condition, msg)
9+
logical, intent(in) :: condition
10+
character(*), intent(in) :: msg
11+
if (.not. condition) error stop msg
12+
end subroutine check
13+
14+
subroutine test_fftpack_ifft
15+
use fftpack, only: fft, ifft
16+
use iso_fortran_env, only: dp => real64
17+
real(kind=dp) :: eps = 1.0e-10
18+
19+
complex(kind=dp) :: x(4)
20+
21+
x = [real(kind=dp) :: 1.0, 2.0, 3.0, 4.0]
22+
23+
call check(sum(abs(ifft(fft(x))/4.0 - [complex(kind=dp) ::(1.0, 0.0), (2.0, 0.0), (3.0, 0.0), (4.0, 0.0)])) < eps, &
24+
msg="abs(sum(ifft(fft(x))/4.0 - [complex(kind=dp) ::(1.0, 0.0), (2.0, 0.0), (3.0, 0.0), (4.0, 0.0)])) < eps failed.")
25+
call check(sum(abs(ifft(fft(x),2) - [complex(kind=dp) ::(8.0, 2.0), (12.0, -2.0)])) < eps, &
26+
msg="abs(sum(ifft(fft(x),2) - [complex(kind=dp) ::(8.0, 2.0), (12.0, -2.0)])) < eps failed.")
27+
call check(sum(abs(ifft(fft(x,2),4) - [complex(kind=dp) ::(2.0, 0.0), (3.0, -1.0), (4.0,0.0), (3.0,1.0)])) < eps, &
28+
msg="abs(sum(ifft(fft(x,2),4) - [complex(kind=dp) ::(2.0, 0.0), (3.0, -1.0), (4.0,0.0), (3.0,1.0)])) < eps failed.")
29+
30+
end subroutine test_fftpack_ifft
31+
32+
end program tester

0 commit comments

Comments
 (0)