init_coul.F90 Source File


Contents

Source Code


Source Code

#include "macros.h"
module init_coul_mod
    use constants, only: dp, int64, sp, pi, stdout
    use util_mod, only: near_zero, stop_all, neci_etime
    better_implicit_none

    private
    public :: gen_ck_fft, gen_zia, initfou

contains

!==========================================================
!.. Routines needed for the initialisation of the Fourier
!.. Method of evaluating the Coulomb integrals
!  ========================================================
    SUBROUTINE INITFOU(NMESHX, CK, NMAX, A, TALPHA, ALPHA, OMEGA, ZIA)
        integer :: NMESHX, NMAX
        complex(dp) CK(NMESHX, NMESHX, NMESHX)
        complex(dp) ZIA(-NMESHX / 2:NMESHX / 2, NMAX, NMAX)
        real(dp) :: ALPHA, OMEGA
        real(dp) A(3), t3
        real(dp) t(2), t1, t2
        LOGICAL TALPHA
        INTEGER, SAVE :: IFIRST = 0
        IF (IFIRST == 1) RETURN
        IFIRST = 1
        T1 = neci_etime(t)
        CALL GEN_CK_FFT(NMESHX, CK, A, TALPHA, ALPHA, OMEGA)
        CALL GEN_ZIA(NMESHX, NMAX, ZIA)
        T2 = neci_etime(t)
        T3 = (T2 - T1)
        WRITE(stdout, *) 'V0=', CK(NMESHX / 2, NMESHX / 2, NMESHX / 2)
        WRITE(stdout, *) ' TIME FOR INITIALISATION:', T3 / 1000.
    END
! =========================================================
    SUBROUTINE GEN_CK_FFT(N, DIST, A, TALPHA, ALPHA, OMEGA)
        integer :: N, I, J, K, N1, N2, N3
        complex(dp) DIST(-N / 2:N / 2 - 1, -N / 2:N / 2 - 1, -N / 2:N / 2 - 1)
        real(dp) A(3), ALPHA2, ALPHA, HSTEPX, HSTEPY, HSTEPZ
        real(dp) :: X, Y, Z, AUX, SUM, G2, GX, GY, GZ, OMEGA, OMEGAP, R
        LOGICAL TALPHA
        character(len=*), parameter :: t_r = "GEN_CK_FFT"
        ALPHA2 = ALPHA * ALPHA
        HSTEPX = 2.0_dp * A(1) / N
        HSTEPY = 2.0_dp * A(2) / N
        HSTEPZ = 2.0_dp * A(3) / N
!..
#if defined(NAGF95) || defined(GFORTRAN_) || defined(BLUEGENE_HACKS)
        call stop_all(t_r, "No ERF in NAG/GFortran?")
#endif
        DO I = -N / 2, N / 2 - 1
        DO J = -N / 2, N / 2 - 1
        DO K = -N / 2, N / 2 - 1
            X = real(I, dp) * HSTEPX
            Y = real(J, dp) * HSTEPY
            Z = real(K, dp) * HSTEPZ
            AUX = X * X + Y * Y + Z * Z
            IF (.not. near_zero(AUX)) THEN
            IF (TALPHA) THEN
                R = SQRT(AUX)
#if !defined(NAGF95) && !defined(GFORTRAN_) && !defined(BLUEGENE_HACKS)
                AUX = 1.0_dp / R * (-1)**(I + J + K) * DERF(R / ALPHA)
#endif
            ELSE
                AUX = 1.0_dp / SQRT(AUX) * (-1)**(I + J + K)
            END IF
            ELSE
            IF (TALPHA) THEN
                AUX = 2.0_dp / SQRT(PI) / ALPHA
            ELSE
                AUX = real(N / 2, dp) * (-1)**(I + J + K)
            END IF
            END IF
            DIST(I, J, K) = CMPLX(AUX, 0.0_dp, dp)
        END DO
        END DO
        END DO
#ifdef __SGI
        N1 = N
        N2 = N
        N3 = N
        LA1 = N1
        LA2 = N2
!..Initialise FFT
        CALL ZFFT3DI(N1, N2, N3, COEFF)
!..FORWARD TRANSFORM
        CALL ZFFT3D(-1, N1, N2, N3, DIST, LA1, LA2, COEFF)
#elif __alpha
        N1 = N
        N2 = N
        N3 = N
        LA1 = N1
        LA2 = N2
        CALL ZFFT_3D('C', 'C', 'F', DIST, DIST, N1, N2, N3, LA1, LA2, 1, 1, 1)
#else
        N1 = N
        N2 = N
        N3 = N
#ifndef DISABLE_FFTW
        CALL DFFTW_PLAN_DFT_3D(PLAN, N1, N2, N3, DIST, DIST, FFTW_FORWARD, FFTW_ESTIMATE)
        CALL DFFTW_EXECUTE(PLAN)
        CALL DFFTW_DESTROY_PLAN(PLAN)
#else
        call stop_all("gen_ck_fft", "FFTW disabled")
#endif
#endif
!..Shift origin and normalise
        DO I = -N / 2, N / 2 - 1
        DO J = -N / 2, N / 2 - 1
        DO K = -N / 2, N / 2 - 1
            DIST(I, J, K) = DIST(I, J, K) * (-1)**(i + j + k) / real(n1 * n2 * n3, dp)
        end do
        end do
        end do
!..the short-range correction for alpha
        IF (TALPHA) THEN
            OMEGAP = 8.0_dp * OMEGA
            DO I = -N / 2, N / 2 - 1
            DO J = -N / 2, N / 2 - 1
            DO K = -N / 2, N / 2 - 1
                GX = PI * I / A(1)
                GY = PI * J / A(2)
                GZ = PI * K / A(3)
                G2 = GX * GX + GY * GY + GZ * GZ
                IF (.not. near_zero(G2)) THEN
                    SUM = 4.0_dp * PI * (1.0_dp - AUX) / OMEGAP / G2
                ELSE
                    SUM = PI * ALPHA2 / OMEGAP
                END IF
                DIST(I, J, K) = DIST(I, J, K) + CMPLX(SUM, 0.0_dp, dp)
            END DO
            END DO
            END DO
        END IF
    END
! ============================================================
    SUBROUTINE GEN_ZIA(KMAX, NMAX, ZIA)
        integer :: K, N, M, KMAX, NMAX
        complex(dp) ZIA(-KMAX / 2:KMAX / 2, NMAX, NMAX)
        DO K = -KMAX / 2, KMAX / 2
            DO N = 1, NMAX
                DO M = 1, NMAX
                    ZIA(K, N, M) = 0.25_dp * (ZIO(N - M + K) + ZIO(-N + M + K) - ZIO(N + M + K) - ZIO(-N - M + K))
                END DO
            END DO
        END DO
    END

    complex(dp) elemental FUNCTION ZIO(K)
        INTEGER, intent(in) :: K
        IF (K == 0) THEN
            ZIO = (1.0_dp, 0.0_dp)
        ELSE
            ZIO = CMPLX(0.0_dp, -((-1.0_dp)**K - 1.0_dp) / (REAL(K, dp) * PI), dp)
        END IF
    END function

end module