quantum-espresso/FFTXlib/fft_interfaces.f90

364 lines
12 KiB
Fortran
Raw Normal View History

!
! Copyright (C) Quantum ESPRESSO group
!
! This file is distributed under the terms of the
! GNU General Public License. See the file `License'
! in the root directory of the present distribution,
! or http://www.gnu.org/copyleft/gpl.txt .
!
!=---------------------------------------------------------------------------=!
MODULE fft_interfaces
IMPLICIT NONE
PRIVATE
PUBLIC :: fwfft, invfft
INTERFACE invfft
!! invfft is the interface to both the standard fft **invfft_x**,
!! and to the "box-grid" version **invfft_b**, used only in CP
!! (the latter has an additional argument)
SUBROUTINE invfft_x( grid_type, f, dfft, dtgs )
USE fft_types, ONLY: fft_type_descriptor
USE task_groups, ONLY: task_groups_descriptor
IMPLICIT NONE
INTEGER, PARAMETER :: DP = selected_real_kind(14,200)
CHARACTER(LEN=*), INTENT(IN) :: grid_type
TYPE(fft_type_descriptor), INTENT(IN) :: dfft
TYPE(task_groups_descriptor), OPTIONAL, INTENT(IN) :: dtgs
COMPLEX(DP) :: f(:)
END SUBROUTINE invfft_x
!
SUBROUTINE invfft_b( f, dfft, ia )
USE fft_smallbox_type, ONLY: fft_box_descriptor
IMPLICIT NONE
INTEGER, PARAMETER :: DP = selected_real_kind(14,200)
INTEGER, INTENT(IN) :: ia
TYPE(fft_box_descriptor), INTENT(IN) :: dfft
COMPLEX(DP) :: f(:)
END SUBROUTINE invfft_b
END INTERFACE
INTERFACE fwfft
SUBROUTINE fwfft_x( grid_type, f, dfft, dtgs )
USE fft_types, ONLY: fft_type_descriptor
USE task_groups, ONLY: task_groups_descriptor
IMPLICIT NONE
INTEGER, PARAMETER :: DP = selected_real_kind(14,200)
CHARACTER(LEN=*), INTENT(IN) :: grid_type
TYPE(fft_type_descriptor), INTENT(IN) :: dfft
TYPE(task_groups_descriptor), OPTIONAL, INTENT(IN) :: dtgs
COMPLEX(DP) :: f(:)
END SUBROUTINE fwfft_x
END INTERFACE
END MODULE fft_interfaces
!=---------------------------------------------------------------------------=!
!
!=---------------------------------------------------------------------------=!
SUBROUTINE invfft_x( grid_type, f, dfft, dtgs )
!! Compute G-space to R-space for a specific grid type
!!
!! **grid_type = 'Dense'** :
!! inverse fourier transform of potentials and charge density f
!! on the dense grid . On output, f is overwritten
!!
!! **grid_type = 'Smooth'** :
!! inverse fourier transform of potentials and charge density f
!! on the smooth grid . On output, f is overwritten
!!
!! **grid_type = 'Wave'** :
!! inverse fourier transform of wave functions f
!! on the smooth grid . On output, f is overwritten
!!
!! **grid_type = 'Custom'** :
!! inverse fourier transform of potentials and charge density f
!! on a custom grid. On output, f is overwritten
!!
!! **grid_type = 'CustomWave'** :
!! inverse fourier transform of wave functions f
!! on a custom grid. On output, f is overwritten
!!
!! **dfft = FFT descriptor**, IMPORTANT NOTICE: grid is specified only by dfft.
!! No check is performed on the correspondence between dfft and grid_type.
!! grid_type is now used only to distinguish cases 'Wave' / 'CustomWave'
!! from all other cases
USE fft_scalar, ONLY: cfft3d, cfft3ds
USE fft_smallbox, ONLY: cft_b, cft_b_omp
USE fft_parallel, ONLY: tg_cft3s
USE fft_types, ONLY: fft_type_descriptor
USE task_groups, ONLY: task_groups_descriptor
IMPLICIT NONE
INTEGER, PARAMETER :: DP = selected_real_kind(14,200)
TYPE(fft_type_descriptor), INTENT(IN) :: dfft
CHARACTER(LEN=*), INTENT(IN) :: grid_type
COMPLEX(DP) :: f(:)
TYPE(task_groups_descriptor), OPTIONAL, INTENT(IN) :: dtgs
!
IF( grid_type == 'Dense' ) THEN
CALL start_clock( 'fft' )
ELSE IF( grid_type == 'Smooth' ) THEN
CALL start_clock( 'ffts' )
ELSE IF( grid_type == 'Wave' ) THEN
CALL start_clock('fftw')
ELSE IF( grid_type == 'Custom' ) THEN
CALL start_clock('fftc')
ELSE IF( grid_type == 'CustomWave' ) THEN
CALL start_clock('fftcw')
ELSE
CALL fftx_error__( ' invfft ', ' unknown grid: '//grid_type , 1 )
END IF
#if defined(__MPI) && !defined __USE_3D_FFT
IF( grid_type == 'Dense' .OR. grid_type == 'Smooth' .OR. &
grid_type == 'Custom' ) THEN
CALL tg_cft3s( f, dfft, 1 )
ELSE IF( grid_type == 'Wave' .OR. grid_type == 'CustomWave' ) THEN
IF( PRESENT( dtgs ) ) THEN
CALL tg_cft3s( f, dfft, 2, dtgs )
ELSE
CALL tg_cft3s( f, dfft, 2 )
END IF
END IF
#else
IF( grid_type == 'Dense' .OR. grid_type == 'Smooth' .OR. &
grid_type == 'Custom' ) THEN
CALL cfft3d( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, 1)
ELSE IF( grid_type == 'Wave' .OR. grid_type == 'CustomWave' ) THEN
#if defined(__MPI) && defined __USE_3D_FFT
CALL cfft3d( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, 1)
#else
CALL cfft3ds( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, 1, &
dfft%isind, dfft%iplw )
#endif
END IF
#endif
IF( grid_type == 'Dense' ) THEN
CALL stop_clock( 'fft' )
ELSE IF( grid_type == 'Smooth' ) THEN
CALL stop_clock( 'ffts' )
ELSE IF( grid_type == 'Wave' ) THEN
CALL stop_clock('fftw')
ELSE IF( grid_type == 'Custom' ) THEN
CALL stop_clock('fftc')
ELSE IF( grid_type == 'CustomWave' ) THEN
CALL stop_clock('fftcw')
END IF
RETURN
END SUBROUTINE invfft_x
!=---------------------------------------------------------------------------=!
!
!=---------------------------------------------------------------------------=!
SUBROUTINE fwfft_x( grid_type, f, dfft, dtgs )
!! Compute R-space to G-space for a specific grid type
!!
!! **grid_type = 'Dense'**
!! forward fourier transform of potentials and charge density f
!! on the dense grid . On output, f is overwritten
!!
!! **grid_type = 'Smooth'**
!! forward fourier transform of potentials and charge density f
!! on the smooth grid . On output, f is overwritten
!!
!! **grid_type = 'Wave'**
!! forward fourier transform of wave functions f
!! on the smooth grid . On output, f is overwritten
!!
!! **grid_type = 'Custom'**
!! forward fourier transform of potentials and charge density f
!! on a custom grid . On output, f is overwritten
!!
!! **grid_type = 'CustomWave'**
!! forward fourier transform of wave functions
!! on a custom grid . On output, f is overwritten
!!
!! **dfft = FFT descriptor**, IMPORTANT NOTICE: grid is specified only by dfft.
!! No check is performed on the correspondence between dfft and grid_type.
!! grid_type is now used only to distinguish cases 'Wave' / 'CustomWave'
!! from all other cases
USE fft_scalar, ONLY: cfft3d, cfft3ds
USE fft_parallel, ONLY: tg_cft3s
USE fft_types, ONLY: fft_type_descriptor
USE task_groups, ONLY: task_groups_descriptor
IMPLICIT NONE
INTEGER, PARAMETER :: DP = selected_real_kind(14,200)
TYPE(fft_type_descriptor), INTENT(IN) :: dfft
CHARACTER(LEN=*), INTENT(IN) :: grid_type
COMPLEX(DP) :: f(:)
TYPE(task_groups_descriptor), OPTIONAL, INTENT(IN) :: dtgs
IF( grid_type == 'Dense' ) THEN
CALL start_clock( 'fft' )
ELSE IF( grid_type == 'Smooth' ) THEN
CALL start_clock( 'ffts' )
ELSE IF( grid_type == 'Wave' ) THEN
CALL start_clock( 'fftw' )
ELSE IF( grid_type == 'Custom' ) THEN
CALL start_clock('fftc')
ELSE IF( grid_type == 'CustomWave' ) THEN
CALL start_clock('fftcw')
ELSE
CALL fftx_error__( ' fwfft ', ' unknown grid: '//grid_type , 1 )
END IF
#if defined(__MPI) && !defined(__USE_3D_FFT)
IF( grid_type == 'Dense' .OR. grid_type == 'Smooth' .OR. &
grid_type == 'Custom' ) THEN
CALL tg_cft3s(f,dfft,-1)
ELSE IF( grid_type == 'Wave' .OR. grid_type == 'CustomWave' ) THEN
IF( PRESENT( dtgs ) ) THEN
CALL tg_cft3s(f,dfft,-2, dtgs )
ELSE
CALL tg_cft3s(f,dfft,-2 )
END IF
END IF
#else
IF( grid_type == 'Dense' .OR. grid_type == 'Smooth' .OR. &
grid_type == 'Custom' ) THEN
CALL cfft3d( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, -1)
ELSE IF( grid_type == 'Wave' .OR. grid_type == 'CustomWave' ) THEN
#if defined(__MPI) && defined(__USE_3D_FFT)
CALL cfft3d( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, -1)
#else
CALL cfft3ds( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, -1, &
dfft%isind, dfft%iplw )
#endif
END IF
#endif
IF( grid_type == 'Dense' ) THEN
CALL stop_clock( 'fft' )
ELSE IF( grid_type == 'Smooth' ) THEN
CALL stop_clock( 'ffts' )
ELSE IF( grid_type == 'Wave' ) THEN
CALL stop_clock( 'fftw' )
ELSE IF( grid_type == 'Custom' ) THEN
CALL stop_clock('fftc')
ELSE IF( grid_type == 'CustomWave' ) THEN
CALL stop_clock('fftcw')
END IF
RETURN
!
END SUBROUTINE fwfft_x
!=---------------------------------------------------------------------------=!
!
!=---------------------------------------------------------------------------=!
SUBROUTINE invfft_b( f, dfft, ia )
!! Not-so-parallel 3d fft for box grid, implemented ONLY for sign=1
!!
!! ComputeG-space to R-space, $$ output = \sum_G f(G)exp(+iG*R) $$
!! The array f (overwritten on output) is NOT distributed:
!! a copy is present on each processor.
!! The fft along z is done on the entire grid.
!! The fft along xy is done ONLY on planes that have components on the
!! dense grid for each processor. Note that the final array will no
!! longer be the same on all processors.
!!
!! **grid_type** = 'Box' (only allowed value!)
!!
!! **dfft** = fft descriptor for the box grid
!!
!! **ia** = index of the atom with a box grid. Used to find the number
!! of planes on this processors, contained in dfft%np3(ia)
USE fft_scalar, ONLY: cfft3d, cfft3ds
USE fft_smallbox, ONLY: cft_b, cft_b_omp
USE fft_parallel, ONLY: tg_cft3s
USE fft_smallbox_type, ONLY: fft_box_descriptor
IMPLICIT NONE
INTEGER, PARAMETER :: DP = selected_real_kind(14,200)
TYPE(fft_box_descriptor), INTENT(IN) :: dfft
! Removed the 'OPTIONAL' attribute. When present, the specific interfaces
! 'invfft_x' and 'invfft_b' cannot be disambiguated when the generic interface
! call is made. This is a violation the Fortran standard. The Cray compiler
! errors out on this, while the Intel only issues a warning. --rbw
! INTEGER, OPTIONAL, INTENT(IN) :: ia
INTEGER, INTENT(IN) :: ia
COMPLEX(DP) :: f(:)
!
INTEGER :: imin3, imax3, np3
! clocks called inside a parallel region do not work properly!
! in the future we probably need a thread safe version of the clock
!$omp master
CALL start_clock( 'fftb' )
!$omp end master
#if defined(__MPI) && !defined(__USE_3D_FFT)
IF( dfft%np3( ia ) > 0 ) THEN
#if defined(__OPENMP)
CALL cft_b_omp( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, &
dfft%imin3( ia ), dfft%imax3( ia ), 1 )
#else
CALL cft_b( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, &
dfft%imin3( ia ), dfft%imax3( ia ), 1 )
#endif
END IF
#else
#if defined(__OPENMP)
CALL cft_b_omp( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, &
dfft%imin3( ia ), dfft%imax3( ia ), 1 )
#else
CALL cfft3d( f, dfft%nr1, dfft%nr2, dfft%nr3, &
dfft%nr1x,dfft%nr2x,dfft%nr3x, 1)
#endif
#endif
!$omp master
CALL stop_clock( 'fftb' )
!$omp end master
RETURN
END SUBROUTINE invfft_b
!=---------------------------------------------------------------------------=!