!------------------------------------------------------------------------------ ! ! This file is part of the Sternheimer-GW code. ! ! Copyright (C) 2010 - 2016 ! Henry Lambert, Martin Schlipf, and Feliciano Giustino ! ! Sternheimer-GW is free software: you can redistribute it and/or modify ! it under the terms of the GNU General Public License as published by ! the Free Software Foundation, either version 3 of the License, or ! (at your option) any later version. ! ! Sternheimer-GW is distributed in the hope that it will be useful, ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! GNU General Public License for more details. ! ! You should have received a copy of the GNU General Public License ! along with Sternheimer-GW. If not, see ! http://www.gnu.org/licenses/gpl.html . ! !------------------------------------------------------------------------------ !> Provide routines for 6 dimensional FFT. !! !! This module allows to do a Fourier transform of quantities that have to !! spacial coordinates into reciprocal space and the reverse !! \f{equation}{ !! f(r, r') \underset{\text{fwfft6}}{\longrightarrow} f(G, G') !! \underset{\text{invfft6}}{\longrightarrow} f(r, r')~. !! \f} MODULE fft6_module IMPLICIT NONE CONTAINS !> Transform an input array \f$f(r, r')\f$ from real to reciprocal space !! \f$f(G, G')\f$. !! !! This is done in the following steps: SUBROUTINE fwfft6(grid_type, f, dfft, map, omega) USE kinds, ONLY: dp USE fft_interfaces, ONLY: fwfft USE fft_types, ONLY: fft_type_descriptor !> grid type used for the Fourier transform, this is passed to fwfft; !! check the definition of fwfft for a list of options CHARACTER(*), INTENT(IN) :: grid_type !> *on input* the array in real space \f$f(r, r')\f$
!! *on output* the array in reciprocal space \f$f(G, G')\f$ COMPLEX(dp), INTENT(INOUT) :: f(:,:) !> FFT descriptor - this defines the way the Fourier transform is !! executed, must be consistent with grid_type !! @note the code does not check explicitly if dfft and grid_type are compatible TYPE(fft_type_descriptor), INTENT(IN) :: dfft !> Because usually a sphere of G-vectors is used, not all points on the FFT !! grid are set. This map points from index of the G-points inside the !! sphere onto their index in the full G-mesh. INTEGER, INTENT(IN) :: map(:) !> volume of the unit cell REAL(dp), INTENT(IN) :: omega !> work array for the second index (which is not contigous in memory COMPLEX(dp), ALLOCATABLE :: work(:) !> number of points in reciprocal space INTEGER num_g !> counter on reciprocal space points INTEGER ig !> number of points in real space INTEGER num_r !> counter on real space points INTEGER ir !> check for error in allocation INTEGER ierr ! initialize helper variables num_g = SIZE(map) num_r = dfft%nnr ! ! sanity test of the input ! ! reduced mesh must be within full mesh IF (ANY(map > num_r)) & CALL errore(__FILE__, "some G vector are outside the mesh of the Fourier transform", 1) ! ! check that f has size compatible with dfft IF (SIZE(f, 1) /= num_r) & CALL errore(__FILE__, "size of array not compatible with Fourier transform", 1) IF (SIZE(f, 2) /= num_r) & CALL errore(__FILE__, "f must be a square matrix", 1) ! create work array ALLOCATE(work(num_r), STAT = ierr) IF (ierr /= 0) & CALL errore(__FILE__, "error allocating the work array", ierr) ! loop over second index DO ir = 1, num_r !! !! 1. we store the conjugate of a row in the work array \f$w(r) = f^\ast(r, r')\f$ !! work = CONJG(f(:, ir)) !! !! 2. we transform the work array \f$w(r) \rightarrow w(G)\f$ !! CALL fwfft(grid_type, work, dfft) !! !! 3. we extract the G vectors inside of the sphere \f$f(G, r') = w^\ast(G)\f$ !! f(:num_g, ir) = CONJG(work(map)) !! END DO ! ir ! loop over first index (now in reciprocal space) DO ig = 1, num_g !! !! 4. we store a column in the work array \f$w(r') = f(G, r')\f$ !! work = f(ig, :) !! !! 5. we tranform the work array \f$w(r') \rightarrow w(G')\f$ !! CALL fwfft(grid_type, work, dfft) !! !! 6. extract the G vectors within the sphere \f$f(G, G') = w(G')\f$ !! f(ig, :num_g) = work(map) * omega !! END DO ! ig END SUBROUTINE fwfft6 !> Transform an input array \f$f(G, G')\f$ from reciprocal to real space !! \f$f(r, r')\f$. !! !! This is done in the following steps: SUBROUTINE invfft6(grid_type, f, dfft, map, omega) USE kinds, ONLY: dp USE fft_interfaces, ONLY: invfft USE fft_types, ONLY: fft_type_descriptor !> grid type used for the Fourier transform, this is passed to invfft; !! check the definition of invfft for a list of options CHARACTER(*), INTENT(IN) :: grid_type !> *on input* the array in reciprocal space \f$f(G, G')\f$
!! *on output* the array in real space \f$f(r, r')\f$ COMPLEX(dp), INTENT(INOUT) :: f(:,:) !> FFT descriptor - this defines the way the Fourier transform is !! executed, must be consistent with grid_type !! @note the code does not check explicitly if dfft and grid_type are compatible TYPE(fft_type_descriptor), INTENT(IN) :: dfft !> Because usually a sphere of G-vectors is used, not all points on the FFT !! grid are set. This map points from index of the G-points inside the !! sphere onto their index in the full G-mesh. INTEGER, INTENT(IN) :: map(:) !> volume of the unit cell REAL(dp), INTENT(IN) :: omega !> complex constant of zero COMPLEX(dp), PARAMETER :: zero = CMPLX(0.0_dp, 0.0_dp, KIND = dp) !> work array for the second index (which is not contigous in memory COMPLEX(dp), ALLOCATABLE :: work(:) !> number of points in reciprocal space INTEGER num_g !> counter on reciprocal space points INTEGER ig !> number of points in real space INTEGER num_r !> counter on real space points INTEGER ir !> check for error in allocation INTEGER ierr ! initialize helper variables num_g = SIZE(map) num_r = dfft%nnr ! ! sanity test of the input ! ! reduced mesh must be within full mesh IF (ANY(map > num_r)) & CALL errore(__FILE__, "some G vector are outside the mesh of the Fourier transform", 1) ! ! check that f has size compatible with dfft IF (SIZE(f, 1) /= num_r) & CALL errore(__FILE__, "size of array not compatible with Fourier transform", 1) IF (SIZE(f, 2) /= num_r) & CALL errore(__FILE__, "f must be a square matrix", 1) ! create work array ALLOCATE(work(num_r), STAT = ierr) IF (ierr /= 0) & CALL errore(__FILE__, "error allocating the work array", ierr) ! loop over first index DO ig = 1, num_g !! !! 1. we store the conjugate of a column in the work array \f$w(G') = f(G, G')\f$ !! ! note - we initialize work, because map only contains a subset of all entries work = zero work(map) = f(ig, :num_g) / omega !! !! 2. we transform the work array \f$w(G') \rightarrow w(r')\f$ !! CALL invfft(grid_type, work, dfft) !! !! 3. we extract the values from the work array \f$f(G, r') = w(r')\f$ !! f(ig, :) = work !! END DO ! ig ! loop over second index (now in real space) DO ir = 1, num_r !! !! 4. we store a row in the work array \f$w(G) = f^\ast(G, r')\f$ !! ! note - we initialize work, because map only contains a subset of all entries work = zero work(map) = CONJG(f(:num_g, ir)) !! !! 5. we tranform the work array \f$w(G) \rightarrow w(r')\f$ !! CALL invfft(grid_type, work, dfft) !! !! 6. extract the values from the work array \f$f(r, r') = w^\ast(G')\f$ !! f(:, ir) = CONJG(work) !! END DO ! ir END SUBROUTINE invfft6 END MODULE fft6_module