Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29271 Discussions

Complex-Complex DFTs fail depending on compiler syntax

roryjohnston
Beginner
245 Views

Hello,

 

In both the same and opposite sense to my previous post (DftiCommitDescriptor fails under Intel-2024 ), Complex-Complex DFTs produce differing results depending on whether you statically or dynamically link the OneAPI library.

 

Here's my reproducer:
```
! cfft_reproducer.f90

program mkl_fft_example
! USE statements must come before IMPLICIT NONE
use MKL_DFTI
implicit none

type(DFTI_DESCRIPTOR), pointer :: handle

#ifdef MKLI8
integer, parameter :: IK = 8
#else
integer, parameter :: IK = 4
#endif

integer(kind=IK) :: i, status, DIM, LEN, STRIDES_IN(2), STRIDES_OUT(2)
real(kind=4) :: PI, fscale, bscale
real(kind=4) :: max_error
complex(kind=4), allocatable :: x(:), y(:)
 
DIM = 1
LEN = 16
STRIDES_IN = (/int(0,IK), int(1, IK)/)
STRIDES_OUT = (/int(0,IK), int(1, IK)/)
fscale = 1.0_4
bscale = 1.0_4 / real(LEN, 4)

PI = 3.14159265_4

! Create and set up FFT descriptor
status = DftiCreateDescriptor(handle, DFTI_SINGLE, DFTI_COMPLEX, DIM, LEN)

status = DftiSetValue(handle, DFTI_PLACEMENT, DFTI_INPLACE)
status = DftiSetValue(handle, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX)

status = DftiSetValue(handle, DFTI_INPUT_DISTANCE, LEN)
status = DftiSetValue(handle, DFTI_OUTPUT_DISTANCE, LEN)

status = DftiSetValue(handle, DFTI_INPUT_STRIDES, STRIDES_IN)
status = DftiSetValue(handle, DFTI_OUTPUT_STRIDES, STRIDES_OUT)

status = DftiSetValue(handle, DFTI_FORWARD_SCALE, bscale)
status = DftiSetValue(handle, DFTI_BACKWARD_SCALE, fscale)

status = DftiCommitDescriptor(handle)
 
if (status /= 0) then
print *, 'Error creating FFT descriptor'
stop
end if
 
allocate(x(LEN))
allocate(y(LEN))

! Initialize input signal: simple sinusoid
do i = 1, LEN
x(i) = cmplx(cos(2.0_4 * PI * (i-1) / LEN), &
sin(2.0_4 * PI * (i-1) / LEN), kind=4)
end do
 
! Save copy for comparison
y(:) = x(:)
 
! Print original signal
print *, 'Original signal:'
do i = 1, LEN
print '(I3,": (",F10.4,",",F10.4,")")', i, real(x(i)), aimag(x(i))
end do
 
! Forward transform
status = DftiComputeForward(handle, x)
 
! Inverse transform
status = DftiComputeBackward(handle, x)
 
print *, ''
print *, 'After inverse FFT (scaled):'

! Compute maximum error
max_error = 0.0_4
do i = 1, LEN
print '(I3,": (",F10.4,",",F10.4,")")', i, real(x(i)), aimag(x(i))
max_error = max(max_error, &
max(abs(real(x(i) - y(i))), abs(aimag(x(i) - y(i)))))
end do

print *, ''
print '("Maximum error: ",E12.4)', max_error
 
! Clean up
status = DftiFreeDescriptor(handle)
 
end program mkl_fft_example
```

Compiled with
```
TARGET = cfft_reproducer
SRC = cfft_reproducer.f90

INCLUDE_FLAGS = -I${MKLROOT}/include/intel64/ilp64

ifdef OLD
##### OLD STYLE #####
FCFLAGS = -qopenmp -Wl,--start-group \
${MKLROOT}/lib/intel64/libmkl_blas95_ilp64.a \
${MKLROOT}/lib/intel64/libmkl_lapack95_ilp64.a \
${MKLROOT}/lib/intel64/libmkl_intel_ilp64.a \
${MKLROOT}/lib/intel64/libmkl_core.a \
${MKLROOT}/lib/intel64/libmkl_intel_thread.a \
-Wl,--end-group
else ifdef NEW
##### NEW STYLE #####
FCFLAGS = -qmkl
endif

$(TARGET): $(SRC)
${FC} -fpp -DMKLI8 $(INCLUDE_FLAGS) -o $(TARGET) $(SRC) $(FCFLAGS)

clean:
rm -f $(TARGET) *.o
```

If I do:

```
module load intel/intel-2021
export FC=ifort
make clean; make OLD=x; ./cfft_reproducer      # compiles, runs successfully
make clean; make NEW=x; ./cfft_reproducer      # compiles, produces incorrect result
```

However, if I do:
```
module load intel/intel-2024
export FC=ifx
make clean; make OLD=x; ./cfft_reproducer     # compiles, runs successfully
make clean; make NEW=x; ./cfft_reproducer      # compiles, produces incorrect result
```
 
By incorrect result, I mean it's skipping the first index (presumably the place where the Nyquist frequency is stored), with the remaining array matching the input.

If someone can please explain this behaviour, I'd appreciate it.

Note:
`module load intel/intel-2021` will point MKLROOT to `.../oneapi-2021.update.4/mkl/2021.4.0`
`module load intel/intel-2024` will point MKLROOT to `.../oneapi-2024.update.1/mkl/2024.1`
0 Kudos
0 Replies
Reply