LCOV - code coverage report
Current view: top level - src/eri_mme - eri_mme_gaussian.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 68 70 97.1 %
Date: 2024-12-21 06:28:57 Functions: 4 4 100.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Methods related to properties of Hermite and Cartesian Gaussian functions.
      10             : !> \par History
      11             : !>       2015 09 created
      12             : !> \author Patrick Seewald
      13             : ! **************************************************************************************************
      14             : 
      15             : MODULE eri_mme_gaussian
      16             :    USE kinds,                           ONLY: dp
      17             :    USE mathconstants,                   ONLY: gamma1
      18             :    USE minimax_exp,                     ONLY: get_exp_minimax_coeff
      19             : #include "../base/base_uses.f90"
      20             : 
      21             :    IMPLICIT NONE
      22             : 
      23             :    PRIVATE
      24             : 
      25             :    LOGICAL, PRIVATE, PARAMETER :: debug_this_module = .FALSE.
      26             : 
      27             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'eri_mme_gaussian'
      28             : 
      29             :    INTEGER, PARAMETER, PUBLIC :: eri_mme_coulomb = 1, &
      30             :                                  eri_mme_yukawa = 2, &
      31             :                                  eri_mme_longrange = 3
      32             : 
      33             :    PUBLIC :: &
      34             :       create_gaussian_overlap_dist_to_hermite, &
      35             :       create_hermite_to_cartesian, &
      36             :       get_minimax_coeff_v_gspace, &
      37             :       hermite_gauss_norm
      38             : 
      39             : CONTAINS
      40             : 
      41             : ! **************************************************************************************************
      42             : !> \brief Create matrix to transform between cartesian and hermite gaussian
      43             : !>        basis functions.
      44             : !> \param zet    exponent
      45             : !> \param l_max ...
      46             : !> \param h_to_c transformation matrix with dimensions (0:l_max, 0:l_max)
      47             : !> \note  is idempotent, so transformation is the same
      48             : !>        in both directions.
      49             : ! **************************************************************************************************
      50     2483557 :    PURE SUBROUTINE create_hermite_to_cartesian(zet, l_max, h_to_c)
      51             :       REAL(KIND=dp), INTENT(IN)                          :: zet
      52             :       INTEGER, INTENT(IN)                                :: l_max
      53             :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:, :), &
      54             :          INTENT(OUT)                                     :: h_to_c
      55             : 
      56             :       INTEGER                                            :: k, l
      57             : 
      58     9934228 :       ALLOCATE (h_to_c(-1:l_max + 1, 0:l_max))
      59    58912129 :       h_to_c(:, :) = 0.0_dp
      60     2483557 :       h_to_c(0, 0) = 1.0_dp
      61     8074188 :       DO l = 0, l_max - 1
      62    25730729 :          DO k = 0, l + 1
      63    23247172 :             h_to_c(k, l + 1) = -(k + 1)*h_to_c(k + 1, l) + 2.0_dp*zet*h_to_c(k - 1, l)
      64             :          END DO
      65             :       END DO
      66             : 
      67     2483557 :    END SUBROUTINE create_hermite_to_cartesian
      68             : 
      69             : ! **************************************************************************************************
      70             : !> \brief Norm of 1d Hermite-Gauss functions
      71             : !> \param zet ...
      72             : !> \param l ...
      73             : !> \return ...
      74             : ! **************************************************************************************************
      75     5198884 :    PURE FUNCTION hermite_gauss_norm(zet, l) RESULT(norm)
      76             :       REAL(KIND=dp), INTENT(IN)                          :: zet
      77             :       INTEGER, DIMENSION(3), INTENT(IN)                  :: l
      78             :       REAL(KIND=dp)                                      :: norm
      79             : 
      80    20795536 :       norm = 1.0_dp/SQRT((2.0_dp*zet)**(SUM(l) - 1.5_dp)*(gamma1(l(1))*gamma1(l(2))*gamma1(l(3))))
      81             : 
      82     5198884 :    END FUNCTION hermite_gauss_norm
      83             : 
      84             : ! **************************************************************************************************
      85             : !> \brief Get minimax coefficient a_i and w_i for approximating
      86             : !>        1/G^2 by sum_i w_i exp(-a_i G^2)
      87             : !> \param n_minimax   Number of minimax terms
      88             : !> \param cutoff      Plane Wave cutoff
      89             : !> \param G_min       Minimum absolute value of G
      90             : !> \param minimax_aw  Minimax coefficients a_i, w_i
      91             : !> \param potential   potential to use. Accepts the following values:
      92             : !>                    1: coulomb potential V(r)=1/r
      93             : !>                    2: yukawa potential V(r)=e(-a*r)/r
      94             : !>                    3: long-range coulomb erf(a*r)/r
      95             : !> \param pot_par     potential parameter a for yukawa V(r)=e(-a*r)/r or long-range coulomb V(r)=erf(a*r)/r
      96             : !> \param err_minimax Maximum error MAX (|1/G^2-\sum_i w_i exp(-a_i G^2)|)
      97             : ! **************************************************************************************************
      98      172380 :    SUBROUTINE get_minimax_coeff_v_gspace(n_minimax, cutoff, G_min, minimax_aw, potential, pot_par, err_minimax)
      99             :       INTEGER, INTENT(IN)                                :: n_minimax
     100             :       REAL(KIND=dp), INTENT(IN)                          :: cutoff, G_min
     101             :       REAL(KIND=dp), DIMENSION(:), INTENT(OUT)           :: minimax_aw
     102             :       INTEGER, INTENT(IN), OPTIONAL                      :: potential
     103             :       REAL(KIND=dp), INTENT(IN), OPTIONAL                :: pot_par
     104             :       REAL(KIND=dp), INTENT(OUT), OPTIONAL               :: err_minimax
     105             : 
     106             :       INTEGER                                            :: potential_prv
     107             :       REAL(KIND=dp)                                      :: dG, G_max, minimax_Rc
     108      172380 :       REAL(KIND=dp), ALLOCATABLE, DIMENSION(:)           :: a, w
     109             : 
     110      172380 :       IF (PRESENT(potential)) THEN
     111      170684 :          potential_prv = potential
     112             :       ELSE
     113             :          potential_prv = eri_mme_coulomb
     114             :       END IF
     115             : 
     116      170684 :       IF (potential_prv > 3) THEN
     117           0 :          CPABORT("unknown potential")
     118             :       END IF
     119             : 
     120      172380 :       IF ((potential_prv >= 2) .AND. .NOT. PRESENT(pot_par)) THEN
     121           0 :          CPABORT("potential parameter pot_par required for yukawa or long-range Coulomb")
     122             :       END IF
     123             : 
     124      172380 :       dG = 1.0E-3 ! Resolution in G to determine error of minimax approximation
     125             : 
     126             :       ! Note: G_c = SQRT(2*cutoff) cutoff in 1 cartesian direction
     127             :       ! G_max = SQRT(3*G_c**2) maximum absolute value of G vector
     128             :       ! Minimax approx. needs to be valid in range [G_min, G_max]
     129             : 
     130             :       ! 1) compute minimax coefficients
     131             : 
     132      172380 :       G_max = SQRT(3.0_dp*2.0_dp*cutoff)
     133      172380 :       CPASSERT(G_max .GT. G_min)
     134      172380 :       IF (potential_prv == eri_mme_coulomb .OR. potential_prv == eri_mme_longrange) THEN
     135      172372 :          minimax_Rc = (G_max/G_min)**2
     136           8 :       ELSEIF (potential_prv == eri_mme_yukawa) THEN
     137           8 :          minimax_Rc = (G_max**2 + pot_par**2)/(G_min**2 + pot_par**2)
     138             :       END IF
     139             : 
     140      172380 :       CALL get_exp_minimax_coeff(n_minimax, minimax_Rc, minimax_aw, err_minimax)
     141             : 
     142      689520 :       ALLOCATE (a(n_minimax)); ALLOCATE (w(n_minimax))
     143     2855414 :       a(:) = minimax_aw(:n_minimax)
     144     2855414 :       w(:) = minimax_aw(n_minimax + 1:)
     145      147282 :       SELECT CASE (potential_prv)
     146             :          ! Scale minimax coefficients to incorporate different Fourier transforms
     147             :       CASE (eri_mme_coulomb)
     148             :          ! FT = 1/G**2
     149     2328436 :          a(:) = a/G_min**2
     150     2328436 :          w(:) = w/G_min**2
     151             :       CASE (eri_mme_yukawa)
     152             :          ! FT = 1/(G**2 + pot_par**2)
     153         128 :          w(:) = w*EXP((-a*pot_par**2)/(G_min**2 + pot_par**2))/(G_min**2 + pot_par**2)
     154         128 :          a(:) = a/(G_min**2 + pot_par**2)
     155             :       CASE (eri_mme_longrange)
     156             :          ! FT = exp(-(G/pot_par)**2)/G**2
     157             :          ! approximating 1/G**2 as for Coulomb:
     158      526850 :          a(:) = a/G_min**2
     159      526850 :          w(:) = w/G_min**2
     160             :          ! incorporate exponential factor:
     161      699230 :          a(:) = a + 1.0_dp/pot_par**2
     162             :       END SELECT
     163    10904516 :       minimax_aw = [a(:), w(:)]
     164             : 
     165      172380 :       IF (PRESENT(err_minimax)) THEN
     166      172380 :          IF (potential_prv == eri_mme_coulomb) THEN
     167      147282 :             err_minimax = err_minimax/G_min**2
     168       25098 :          ELSEIF (potential_prv == eri_mme_yukawa) THEN
     169           8 :             err_minimax = err_minimax/(G_min**2 + pot_par**2)
     170       25090 :          ELSEIF (potential_prv == eri_mme_longrange) THEN
     171       25090 :             err_minimax = err_minimax/G_min**2 ! approx. of Coulomb
     172       25090 :             err_minimax = err_minimax*EXP(-G_min**2/pot_par**2) ! exponential factor
     173             :          END IF
     174             :       END IF
     175             : 
     176      172380 :    END SUBROUTINE get_minimax_coeff_v_gspace
     177             : 
     178             : ! **************************************************************************************************
     179             : !> \brief Expand 1d product of cartesian (or hermite) gaussians into single hermite gaussians:
     180             : !>        Find E_t^{lm} s.t.
     181             : !>        F(l, a, r-R1) * F(m, b, r-R2) = sum_{t=0}^{l+m} E_t^{lm} H(t, p, r-R_P)
     182             : !>        with p = a + b, R_P = (a*R1 + b*R2)/p. The function F can be either Cartesian
     183             : !>        Gaussian or Hermite Gaussian.
     184             : !> \param l ...
     185             : !> \param m ...
     186             : !> \param a ...
     187             : !> \param b ...
     188             : !> \param R1 ...
     189             : !> \param R2 ...
     190             : !> \param H_or_C_product 1: cartesian product, 2: hermite product
     191             : !> \param E ...
     192             : ! **************************************************************************************************
     193     2232345 :    PURE SUBROUTINE create_gaussian_overlap_dist_to_hermite(l, m, a, b, R1, R2, H_or_C_product, E)
     194             :       INTEGER, INTENT(IN)                                :: l, m
     195             :       REAL(KIND=dp), INTENT(IN)                          :: a, b, R1, R2
     196             :       INTEGER, INTENT(IN)                                :: H_or_C_product
     197             :       REAL(KIND=dp), DIMENSION(-1:l+m+1, -1:l, -1:m), &
     198             :          INTENT(OUT)                                     :: E
     199             : 
     200             :       INTEGER                                            :: ll, mm, t
     201             :       REAL(KIND=dp)                                      :: c1, c2, c3
     202             : 
     203    81759456 :       E(:, :, :) = 0.0_dp
     204     2232345 :       E(0, 0, 0) = EXP(-a*b/(a + b)*(R1 - R2)**2) ! cost: exp_w flops
     205             : 
     206     2232345 :       c1 = 0.5_dp/(a + b)
     207     2232345 :       c2 = (b/(a + b))*(R2 - R1)
     208     2232345 :       c3 = (a/(a + b))*(R1 - R2)
     209             : 
     210     2232345 :       IF (H_or_C_product .EQ. 1) THEN ! Cartesian overlap dist
     211     2627658 :          DO mm = 0, m
     212     5013384 :             DO ll = 0, l
     213    10674180 :                DO t = 0, ll + mm + 1
     214     6673956 :                   IF (ll .LT. l) THEN
     215             :                      E(t, ll + 1, mm) = c1*E(t - 1, ll, mm) + & ! cost: 8 flops
     216             :                                         c2*E(t, ll, mm) + &
     217     1988118 :                                         (t + 1)*E(t + 1, ll, mm)
     218             :                   END IF
     219     9059682 :                   IF (mm .LT. m) THEN
     220             :                      E(t, ll, mm + 1) = c1*E(t - 1, ll, mm) + & ! cost: 8 flops
     221             :                                         c3*E(t, ll, mm) + &
     222     2342994 :                                         (t + 1)*E(t + 1, ll, mm)
     223             :                   END IF
     224             :                END DO
     225             :             END DO
     226             :          END DO
     227             :       ELSE ! Hermite overlap dist
     228     2960643 :          DO mm = 0, m
     229     5620305 :             DO ll = 0, l
     230    11931531 :                DO t = 0, ll + mm + 1
     231     7530411 :                   IF (ll .LT. l) THEN
     232             :                      E(t, ll + 1, mm) = a*(2*c1*E(t - 1, ll, mm) + & ! cost: 16 flops
     233             :                                            2*c2*E(t, ll, mm) + &
     234             :                                            2*(t + 1)*E(t + 1, ll, mm) - &
     235     2526669 :                                            2*ll*E(t, ll - 1, mm))
     236             :                   END IF
     237    10190073 :                   IF (mm .LT. m) THEN
     238             :                      E(t, ll, mm + 1) = b*(2*c1*E(t - 1, ll, mm) + & ! cost: 16 flops
     239             :                                            2*c3*E(t, ll, mm) + &
     240             :                                            2*(t + 1)*E(t + 1, ll, mm) - &
     241     2529750 :                                            2*mm*E(t, ll, mm - 1))
     242             : 
     243             :                   END IF
     244             :                END DO
     245             :             END DO
     246             :          END DO
     247             :       END IF
     248             : 
     249     2232345 :    END SUBROUTINE create_gaussian_overlap_dist_to_hermite
     250             : END MODULE eri_mme_gaussian

Generated by: LCOV version 1.15