LCOV - code coverage report
Current view: top level - src - semi_empirical_mpole_methods.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:2fce0f8) Lines: 112 113 99.1 %
Date: 2024-12-21 06:28:57 Functions: 3 3 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 Setup and Methods for semi-empirical multipole types
      10             : !> \author Teodoro Laino [tlaino] - 08.2008 Zurich University
      11             : ! **************************************************************************************************
      12             : MODULE semi_empirical_mpole_methods
      13             : 
      14             :    USE input_constants,                 ONLY: do_method_pnnl
      15             :    USE kinds,                           ONLY: dp
      16             :    USE semi_empirical_int_arrays,       ONLY: alm,&
      17             :                                               indexa,&
      18             :                                               indexb,&
      19             :                                               se_map_alm
      20             :    USE semi_empirical_mpole_types,      ONLY: nddo_mpole_create,&
      21             :                                               nddo_mpole_release,&
      22             :                                               nddo_mpole_type,&
      23             :                                               semi_empirical_mpole_p_create,&
      24             :                                               semi_empirical_mpole_p_type,&
      25             :                                               semi_empirical_mpole_type
      26             :    USE semi_empirical_par_utils,        ONLY: amn_l
      27             :    USE semi_empirical_types,            ONLY: semi_empirical_type
      28             : #include "./base/base_uses.f90"
      29             : 
      30             :    IMPLICIT NONE
      31             : 
      32             :    PRIVATE
      33             : 
      34             : ! *** Global parameters ***
      35             :    LOGICAL, PARAMETER, PRIVATE          :: debug_this_module = .FALSE.
      36             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'semi_empirical_mpole_methods'
      37             : 
      38             :    PUBLIC :: semi_empirical_mpole_p_setup, &
      39             :              nddo_mpole_setup, &
      40             :              quadrupole_sph_to_cart
      41             : 
      42             : CONTAINS
      43             : 
      44             : ! **************************************************************************************************
      45             : !> \brief Setup semi-empirical mpole type
      46             : !>        This function setup for each semi-empirical type a structure containing
      47             : !>        the multipolar expansion for all possible combination on-site of atomic
      48             : !>        orbitals ( \mu \nu |
      49             : !> \param mpoles ...
      50             : !> \param se_parameter ...
      51             : !> \param method ...
      52             : !> \date   09.2008
      53             : !> \author Teodoro Laino [tlaino] - University of Zurich
      54             : ! **************************************************************************************************
      55        3964 :    SUBROUTINE semi_empirical_mpole_p_setup(mpoles, se_parameter, method)
      56             :       TYPE(semi_empirical_mpole_p_type), DIMENSION(:), &
      57             :          POINTER                                         :: mpoles
      58             :       TYPE(semi_empirical_type), POINTER                 :: se_parameter
      59             :       INTEGER, INTENT(IN)                                :: method
      60             : 
      61             :       CHARACTER(LEN=3), DIMENSION(9), PARAMETER :: &
      62             :          label_print_orb = (/"  s", " px", " py", " pz", "dx2", "dzx", "dz2", "dzy", "dxy"/)
      63             :       INTEGER, DIMENSION(9), PARAMETER :: loc_index = (/1, 2, 2, 2, 3, 3, 3, 3, 3/)
      64             : 
      65             :       INTEGER                                            :: a, b, i, ind1, ind2, j, k, k1, k2, mu, &
      66             :                                                             natorb, ndim, nr
      67             :       REAL(KIND=dp)                                      :: dlm, tmp, wp, ws, zb, ZP, ZS, zt
      68             :       REAL(KIND=dp), DIMENSION(3, 3, 45)                 :: M2
      69             :       REAL(KIND=dp), DIMENSION(3, 45)                    :: M1
      70             :       REAL(KIND=dp), DIMENSION(45)                       :: M0
      71             :       REAL(KIND=dp), DIMENSION(6, 0:2)                   :: amn
      72             :       TYPE(semi_empirical_mpole_type), POINTER           :: mpole
      73             : 
      74        3964 :       CPASSERT(.NOT. ASSOCIATED(mpoles))
      75             :       ! If there are atomic orbitals proceed with the expansion in multipoles
      76        3964 :       natorb = se_parameter%natorb
      77        3964 :       IF (natorb /= 0) THEN
      78        2240 :          ndim = natorb*(natorb + 1)/2
      79        2240 :          CALL semi_empirical_mpole_p_create(mpoles, ndim)
      80             : 
      81             :          ! Select method for multipolar expansion
      82             : 
      83             :          ! Fill in information on multipole expansion due to atomic orbitals charge
      84             :          ! distribution
      85        2240 :          NULLIFY (mpole)
      86        2240 :          CALL amn_l(se_parameter, amn)
      87       13486 :          DO i = 1, natorb
      88       57504 :             DO j = 1, i
      89       44018 :                ind1 = indexa(se_map_alm(i), se_map_alm(j))
      90       44018 :                ind2 = indexb(i, j)
      91             :                ! the order in the mpoles structure is like the standard one for the
      92             :                ! integrals: s px py pz dx2-y2 dzx dz2 dzy dxy (lower triangular)
      93             :                ! which differs from the order of the Hamiltonian in CP2K. But I
      94             :                ! preferred to keep this order for consistency with the integrals
      95       44018 :                mpole => mpoles(ind2)%mpole
      96       44018 :                mpole%indi = i
      97       44018 :                mpole%indj = j
      98       44018 :                a = loc_index(i)
      99       44018 :                b = loc_index(j)
     100       44018 :                mpole%c = HUGE(0.0_dp)
     101      176072 :                mpole%d = HUGE(0.0_dp)
     102      264108 :                mpole%qs = HUGE(0.0_dp)
     103      572234 :                mpole%qc = HUGE(0.0_dp)
     104             : 
     105             :                ! Charge
     106       44018 :                IF (alm(ind1, 0, 0) /= 0.0_dp) THEN
     107       11246 :                   dlm = 1.0_dp/SQRT(REAL((2*0 + 1), KIND=dp))
     108       11246 :                   tmp = -dlm*amn(indexb(a, b), 0)
     109       11246 :                   mpole%c = tmp*alm(ind1, 0, 0)
     110       11246 :                   mpole%task(1) = .TRUE.
     111             :                END IF
     112             : 
     113             :                ! Dipole
     114      149204 :                IF (ANY(alm(ind1, 1, -1:1) /= 0.0_dp)) THEN
     115       13434 :                   dlm = 1.0_dp/SQRT(REAL((2*1 + 1), KIND=dp))
     116       13434 :                   tmp = -dlm*amn(indexb(a, b), 1)
     117       13434 :                   mpole%d(1) = tmp*alm(ind1, 1, 1)
     118       13434 :                   mpole%d(2) = tmp*alm(ind1, 1, -1)
     119       13434 :                   mpole%d(3) = tmp*alm(ind1, 1, 0)
     120       13434 :                   mpole%task(2) = .TRUE.
     121             :                END IF
     122             : 
     123             :                ! Quadrupole
     124      186602 :                IF (ANY(alm(ind1, 2, -2:2) /= 0.0_dp)) THEN
     125       23916 :                   dlm = 1.0_dp/SQRT(REAL((2*2 + 1), KIND=dp))
     126       23916 :                   tmp = -dlm*amn(indexb(a, b), 2)
     127             : 
     128             :                   ! Spherical components
     129       23916 :                   mpole%qs(1) = tmp*alm(ind1, 2, 0) ! d3z2-r2
     130       23916 :                   mpole%qs(2) = tmp*alm(ind1, 2, 1) ! dzx
     131       23916 :                   mpole%qs(3) = tmp*alm(ind1, 2, -1) ! dzy
     132       23916 :                   mpole%qs(4) = tmp*alm(ind1, 2, 2) ! dx2-y2
     133       23916 :                   mpole%qs(5) = tmp*alm(ind1, 2, -2) ! dxy
     134             : 
     135             :                   ! Convert into cartesian components
     136       23916 :                   CALL quadrupole_sph_to_cart(mpole%qc, mpole%qs)
     137       23916 :                   mpole%task(3) = .TRUE.
     138             :                END IF
     139             : 
     140       11246 :                IF (debug_this_module) THEN
     141             :                   WRITE (*, '(A,2I6,A)') "Orbitals ", i, j, &
     142             :                      " ("//label_print_orb(i)//","//label_print_orb(j)//")"
     143             :                   IF (mpole%task(1)) WRITE (*, '(9F12.6)') mpole%c
     144             :                   IF (mpole%task(2)) WRITE (*, '(9F12.6)') mpole%d
     145             :                   IF (mpole%task(3)) WRITE (*, '(9F12.6)') mpole%qc
     146             :                   WRITE (*, *)
     147             :                END IF
     148             :             END DO
     149             :          END DO
     150             : 
     151        2240 :          IF (method == do_method_pnnl) THEN
     152             :             ! No d-function for Schenter type integrals
     153          28 :             CPASSERT(natorb <= 4)
     154             : 
     155          28 :             M0 = 0.0_dp
     156          28 :             M1 = 0.0_dp
     157          28 :             M2 = 0.0_dp
     158             : 
     159         140 :             DO mu = 1, se_parameter%natorb
     160         140 :                M0(indexb(mu, mu)) = 1.0_dp
     161             :             END DO
     162             : 
     163          28 :             ZS = se_parameter%sto_exponents(0)
     164          28 :             ZP = se_parameter%sto_exponents(1)
     165          28 :             nr = se_parameter%nr
     166             : 
     167          28 :             ws = REAL((2*nr + 2)*(2*nr + 1), dp)/(24.0_dp*ZS**2)
     168         112 :             DO k = 1, 3
     169         112 :                M2(k, k, indexb(1, 1)) = ws
     170             :             END DO
     171             : 
     172          28 :             IF (ZP > 0._dp) THEN
     173          28 :                zt = SQRT(ZS*ZP)
     174          28 :                zb = 0.5_dp*(ZS + ZP)
     175         112 :                DO k = 1, 3
     176         112 :                   M1(k, indexb(1, 1 + k)) = (zt/zb)**(2*nr + 1)*REAL(2*nr + 1, dp)/(2.0*zb*SQRT(3.0_dp))
     177             :                END DO
     178             : 
     179          28 :                wp = REAL((2*nr + 2)*(2*nr + 1), dp)/(40.0_dp*ZP**2)
     180         112 :                DO k1 = 1, 3
     181         364 :                   DO k2 = 1, 3
     182         336 :                      IF (k1 == k2) THEN
     183          84 :                         M2(k2, k2, indexb(1 + k1, 1 + k1)) = 3.0_dp*wp
     184             :                      ELSE
     185         168 :                         M2(k2, k2, indexb(1 + k1, 1 + k1)) = wp
     186             :                      END IF
     187             :                   END DO
     188             :                END DO
     189          28 :                M2(1, 2, indexb(1 + 1, 1 + 2)) = wp
     190          28 :                M2(2, 1, indexb(1 + 1, 1 + 2)) = wp
     191          28 :                M2(2, 3, indexb(1 + 2, 1 + 3)) = wp
     192          28 :                M2(3, 2, indexb(1 + 2, 1 + 3)) = wp
     193          28 :                M2(3, 1, indexb(1 + 3, 1 + 1)) = wp
     194          28 :                M2(1, 3, indexb(1 + 3, 1 + 1)) = wp
     195             :             END IF
     196             : 
     197         140 :             DO i = 1, natorb
     198         420 :                DO j = 1, i
     199         280 :                   ind1 = indexa(se_map_alm(i), se_map_alm(j))
     200         280 :                   ind2 = indexb(i, j)
     201         280 :                   mpole => mpoles(ind2)%mpole
     202         280 :                   mpole%indi = i
     203         280 :                   mpole%indj = j
     204             :                   ! Charge
     205         280 :                   mpole%cs = -M0(indexb(i, j))
     206             :                   ! Dipole
     207        1120 :                   mpole%ds = -M1(1:3, indexb(i, j))
     208             :                   ! Quadrupole
     209        3640 :                   mpole%qq = -3._dp*M2(1:3, 1:3, indexb(i, j))
     210         112 :                   IF (debug_this_module) THEN
     211             :                      WRITE (*, '(A,2I6,A)') "Orbitals ", i, j, &
     212             :                         " ("//label_print_orb(i)//","//label_print_orb(j)//")"
     213             :                      WRITE (*, '(9F12.6)') mpole%cs
     214             :                      WRITE (*, '(9F12.6)') mpole%ds
     215             :                      WRITE (*, '(9F12.6)') mpole%qq
     216             :                      WRITE (*, *)
     217             :                   END IF
     218             :                END DO
     219             :             END DO
     220             :          ELSE
     221        2212 :             mpole%cs = mpole%c
     222        8848 :             mpole%ds = mpole%d
     223       28756 :             mpole%qq = mpole%qc
     224             :          END IF
     225             :       END IF
     226             : 
     227        3964 :    END SUBROUTINE semi_empirical_mpole_p_setup
     228             : 
     229             : ! **************************************************************************************************
     230             : !> \brief  Transforms the quadrupole components from sphericals to cartesians
     231             : !> \param qcart ...
     232             : !> \param qsph ...
     233             : !> \date   09.2008
     234             : !> \author Teodoro Laino [tlaino] - University of Zurich
     235             : ! **************************************************************************************************
     236       49098 :    SUBROUTINE quadrupole_sph_to_cart(qcart, qsph)
     237             :       REAL(KIND=dp), DIMENSION(3, 3), INTENT(OUT)        :: qcart
     238             :       REAL(KIND=dp), DIMENSION(5), INTENT(IN)            :: qsph
     239             : 
     240             : ! Notation
     241             : !          qs(1) - d3z2-r2
     242             : !          qs(2) - dzx
     243             : !          qs(3) - dzy
     244             : !          qs(4) - dx2-y2
     245             : !          qs(5) - dxy
     246             : ! Cartesian components
     247             : 
     248       49098 :       qcart(1, 1) = (qsph(4) - qsph(1)/SQRT(3.0_dp))*SQRT(3.0_dp)/2.0_dp
     249       49098 :       qcart(2, 1) = qsph(5)*SQRT(3.0_dp)/2.0_dp
     250       49098 :       qcart(3, 1) = qsph(2)*SQRT(3.0_dp)/2.0_dp
     251       49098 :       qcart(2, 2) = -(qsph(4) + qsph(1)/SQRT(3.0_dp))*SQRT(3.0_dp)/2.0_dp
     252       49098 :       qcart(3, 2) = qsph(3)*SQRT(3.0_dp)/2.0_dp
     253       49098 :       qcart(3, 3) = qsph(1)
     254             :       ! Symmetrize tensor
     255       49098 :       qcart(1, 2) = qcart(2, 1)
     256       49098 :       qcart(1, 3) = qcart(3, 1)
     257       49098 :       qcart(2, 3) = qcart(3, 2)
     258             : 
     259       49098 :    END SUBROUTINE quadrupole_sph_to_cart
     260             : 
     261             : ! **************************************************************************************************
     262             : !> \brief Setup NDDO multipole type
     263             : !> \param nddo_mpole ...
     264             : !> \param natom ...
     265             : !> \date   09.2008
     266             : !> \author Teodoro Laino [tlaino] - University of Zurich
     267             : ! **************************************************************************************************
     268          32 :    SUBROUTINE nddo_mpole_setup(nddo_mpole, natom)
     269             :       TYPE(nddo_mpole_type), POINTER                     :: nddo_mpole
     270             :       INTEGER, INTENT(IN)                                :: natom
     271             : 
     272             :       CHARACTER(len=*), PARAMETER                        :: routineN = 'nddo_mpole_setup'
     273             : 
     274             :       INTEGER                                            :: handle
     275             : 
     276          32 :       CALL timeset(routineN, handle)
     277             : 
     278          32 :       IF (ASSOCIATED(nddo_mpole)) THEN
     279           0 :          CALL nddo_mpole_release(nddo_mpole)
     280             :       END IF
     281          32 :       CALL nddo_mpole_create(nddo_mpole)
     282             :       ! Allocate Global Arrays
     283          96 :       ALLOCATE (nddo_mpole%charge(natom))
     284          96 :       ALLOCATE (nddo_mpole%dipole(3, natom))
     285          96 :       ALLOCATE (nddo_mpole%quadrupole(3, 3, natom))
     286             : 
     287          96 :       ALLOCATE (nddo_mpole%efield0(natom))
     288          96 :       ALLOCATE (nddo_mpole%efield1(3, natom))
     289          96 :       ALLOCATE (nddo_mpole%efield2(9, natom))
     290             : 
     291          32 :       CALL timestop(handle)
     292             : 
     293          32 :    END SUBROUTINE nddo_mpole_setup
     294             : 
     295             : END MODULE semi_empirical_mpole_methods

Generated by: LCOV version 1.15