LCOV - code coverage report
Current view: top level - src/aobasis - orbital_transformation_matrices.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:34ef472) Lines: 127 134 94.8 %
Date: 2024-04-26 08:30:29 Functions: 4 5 80.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 Calculation of the spherical harmonics and the corresponding orbital
      10             : !>        transformation matrices.
      11             : !> \par Literature
      12             : !>      H. B. Schlegel, M. J. Frisch, Int. J. Quantum Chem. 54, 83 (1995)
      13             : !> \par History
      14             : !>      - restructured and cleaned (20.05.2004,MK)
      15             : !> \author Matthias Krack (08.06.2000)
      16             : ! **************************************************************************************************
      17             : MODULE orbital_transformation_matrices
      18             : 
      19             :    USE kinds,                           ONLY: dp
      20             :    USE mathconstants,                   ONLY: dfac,&
      21             :                                               fac,&
      22             :                                               pi
      23             :    USE mathlib,                         ONLY: binomial
      24             :    USE orbital_pointers,                ONLY: co,&
      25             :                                               nco,&
      26             :                                               ncoset,&
      27             :                                               nso,&
      28             :                                               nsoset
      29             :    USE orbital_symbols,                 ONLY: cgf_symbol,&
      30             :                                               sgf_symbol
      31             : 
      32             : !$ USE OMP_LIB, ONLY: omp_get_level
      33             : 
      34             : #include "../base/base_uses.f90"
      35             : 
      36             :    IMPLICIT NONE
      37             : 
      38             :    PRIVATE
      39             : 
      40             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'orbital_transformation_matrices'
      41             : 
      42             :    TYPE orbtramat_type
      43             :       REAL(KIND=dp), DIMENSION(:, :), POINTER :: c2s => NULL(), slm => NULL(), &
      44             :                                                  slm_inv => NULL(), s2c => NULL()
      45             :    END TYPE orbtramat_type
      46             : 
      47             :    TYPE(orbtramat_type), DIMENSION(:), POINTER :: orbtramat => NULL()
      48             : 
      49             :    INTEGER, SAVE :: current_maxl = -1
      50             : 
      51             :    ! Public variables
      52             : 
      53             :    PUBLIC :: orbtramat
      54             : 
      55             :    ! Public subroutines
      56             : 
      57             :    PUBLIC :: deallocate_spherical_harmonics, &
      58             :              init_spherical_harmonics
      59             : 
      60             : CONTAINS
      61             : 
      62             : ! **************************************************************************************************
      63             : !> \brief  Allocate and initialize the orbital transformation matrices for
      64             : !>         the transformation and for the backtransformation of orbitals
      65             : !>         from the Cartesian representation to the spherical representation.
      66             : !> \param maxl ...
      67             : !> \date    20.05.2004
      68             : !> \author  MK
      69             : !> \version 1.0
      70             : ! **************************************************************************************************
      71        6182 :    SUBROUTINE create_spherical_harmonics(maxl)
      72             : 
      73             :       INTEGER, INTENT(IN)                                :: maxl
      74             : 
      75             :       INTEGER                                            :: expo, i, ic, ic1, ic2, is, j, k, l, lx, &
      76             :                                                             lx1, lx2, ly, ly1, ly2, lz, lz1, lz2, &
      77             :                                                             m, ma, nc, ns
      78             :       REAL(KIND=dp)                                      :: s, s1, s2
      79             : 
      80        6182 : !$    IF (omp_get_level() > 0) &
      81           0 : !$       CPABORT("create_spherical_harmonics is not thread-safe")
      82             : 
      83        6182 :       IF (current_maxl > -1) THEN
      84             :          CALL cp_abort(__LOCATION__, &
      85             :                        "Spherical harmonics are already allocated. "// &
      86           0 :                        "Use the init routine for an update")
      87             :       END IF
      88             : 
      89        6182 :       IF (maxl < 0) THEN
      90             :          CALL cp_abort(__LOCATION__, &
      91             :                        "A negative maximum angular momentum quantum "// &
      92           0 :                        "number is invalid")
      93             :       END IF
      94             : 
      95       51446 :       ALLOCATE (orbtramat(0:maxl))
      96        6182 :       nc = ncoset(maxl)
      97        6182 :       ns = nsoset(maxl)
      98             : 
      99       39082 :       DO l = 0, maxl
     100       32900 :          nc = nco(l)
     101       32900 :          ns = nso(l)
     102      131600 :          ALLOCATE (orbtramat(l)%c2s(ns, nc))
     103     2791214 :          orbtramat(l)%c2s = 0.0_dp
     104      131600 :          ALLOCATE (orbtramat(l)%s2c(ns, nc))
     105     2791214 :          orbtramat(l)%s2c = 0.0_dp
     106      131600 :          ALLOCATE (orbtramat(l)%slm(ns, nc))
     107     2791214 :          orbtramat(l)%slm = 0.0_dp
     108      131600 :          ALLOCATE (orbtramat(l)%slm_inv(ns, nc))
     109     2797396 :          orbtramat(l)%slm_inv = 0.0_dp
     110             :       END DO
     111             : 
     112             :       ! Loop over all angular momentum quantum numbers l
     113             : 
     114       39082 :       DO l = 0, maxl
     115             : 
     116             :          ! Build the orbital transformation matrix for the transformation
     117             :          ! from Cartesian to spherical orbitals (c2s, formula 15)
     118             : 
     119      141863 :          DO lx = 0, l
     120      427733 :             DO ly = 0, l - lx
     121      285870 :                lz = l - lx - ly
     122      285870 :                ic = co(lx, ly, lz)
     123     2867277 :                DO m = -l, l
     124     2472444 :                   is = l + m + 1
     125     2472444 :                   ma = ABS(m)
     126     2472444 :                   j = lx + ly - ma
     127     2758314 :                   IF ((j >= 0) .AND. (MODULO(j, 2) == 0)) THEN
     128     1014728 :                      j = j/2
     129     1014728 :                      s1 = 0.0_dp
     130     2998144 :                      DO i = 0, (l - ma)/2
     131     1983416 :                         s2 = 0.0_dp
     132     5767080 :                         DO k = 0, j
     133     3103091 :                            IF (((m < 0) .AND. (MODULO(ABS(ma - lx), 2) == 1)) .OR. &
     134     3783664 :                                ((m > 0) .AND. (MODULO(ABS(ma - lx), 2) == 0))) THEN
     135     1451930 :                               expo = (ma - lx + 2*k)/2
     136     1451930 :                               s = (-1.0_dp)**expo*SQRT(2.0_dp)
     137     2331734 :                            ELSE IF ((m == 0) .AND. (MODULO(lx, 2) == 0)) THEN
     138      568820 :                               expo = k - lx/2
     139      568820 :                               s = (-1.0_dp)**expo
     140             :                            ELSE
     141             :                               s = 0.0_dp
     142             :                            END IF
     143     5767080 :                            s2 = s2 + binomial(j, k)*binomial(ma, lx - 2*k)*s
     144             :                         END DO
     145             :                         s1 = s1 + binomial(l, i)*binomial(i, j)* &
     146     2998144 :                              (-1.0_dp)**i*fac(2*l - 2*i)/fac(l - ma - 2*i)*s2
     147             :                      END DO
     148             :                      orbtramat(l)%c2s(is, ic) = &
     149             :                         SQRT((fac(2*lx)*fac(2*ly)*fac(2*lz)*fac(l)*fac(l - ma))/ &
     150             :                              (fac(lx)*fac(ly)*fac(lz)*fac(2*l)*fac(l + ma)))*s1/ &
     151     1014728 :                         (2.0_dp**l*fac(l))
     152             :                   ELSE
     153     1457716 :                      orbtramat(l)%c2s(is, ic) = 0.0_dp
     154             :                   END IF
     155             :                END DO
     156             :             END DO
     157             :          END DO
     158             : 
     159             :          ! Build the corresponding transformation matrix for the transformation from
     160             :          ! spherical to Cartesian orbitals (s2c = s*TRANSPOSE(c2s), formulas 18 and 19)
     161             : 
     162      141863 :          DO lx1 = 0, l
     163      427733 :             DO ly1 = 0, l - lx1
     164      285870 :                lz1 = l - lx1 - ly1
     165      285870 :                ic1 = co(lx1, ly1, lz1)
     166             :                s1 = SQRT((fac(lx1)*fac(ly1)*fac(lz1))/ &
     167      285870 :                          (fac(2*lx1)*fac(2*ly1)*fac(2*lz1)))
     168     1773990 :                DO lx2 = 0, l
     169     6110763 :                   DO ly2 = 0, l - lx2
     170     4445736 :                      lz2 = l - lx2 - ly2
     171     4445736 :                      ic2 = co(lx2, ly2, lz2)
     172     4445736 :                      lx = lx1 + lx2
     173     4445736 :                      ly = ly1 + ly2
     174     4445736 :                      lz = lz1 + lz2
     175             :                      IF ((MODULO(lx, 2) == 0) .AND. &
     176     4445736 :                          (MODULO(ly, 2) == 0) .AND. &
     177     1379157 :                          (MODULO(lz, 2) == 0)) THEN
     178             :                         s2 = SQRT((fac(lx2)*fac(ly2)*fac(lz2))/ &
     179     1218642 :                                   (fac(2*lx2)*fac(2*ly2)*fac(2*lz2)))
     180             :                         s = fac(lx)*fac(ly)*fac(lz)*s1*s2/ &
     181     1218642 :                             (fac(lx/2)*fac(ly/2)*fac(lz/2))
     182    14202402 :                         DO is = 1, nso(l)
     183             :                            orbtramat(l)%s2c(is, ic1) = orbtramat(l)%s2c(is, ic1) + &
     184    14202402 :                                                        s*orbtramat(l)%c2s(is, ic2)
     185             :                         END DO
     186             :                      END IF
     187             :                   END DO
     188             :                END DO
     189             :             END DO
     190             :          END DO
     191             : 
     192             :          ! Build up the real spherical harmonics
     193             : 
     194       32900 :          s = SQRT(0.25_dp*dfac(2*l + 1)/pi)
     195             : 
     196      148045 :          DO lx = 0, l
     197      427733 :             DO ly = 0, l - lx
     198      285870 :                lz = l - lx - ly
     199      285870 :                ic = co(lx, ly, lz)
     200     2867277 :                DO m = -l, l
     201     2472444 :                   is = l + m + 1
     202     2472444 :                   s1 = SQRT(dfac(2*lx - 1)*dfac(2*ly - 1)*dfac(2*lz - 1))
     203     2472444 :                   orbtramat(l)%slm(is, ic) = s*orbtramat(l)%c2s(is, ic)/s1
     204             :                   !MK s2 = (-1.0_dp)**m*s ! alternative S(lm) definition
     205             :                   !MK orbtramat(l)%slm(is, ic) = s2*orbtramat(l)%c2s(is,ic)/s1
     206     2758314 :                   orbtramat(l)%slm_inv(is, ic) = s1*orbtramat(l)%s2c(is, ic)/s
     207             :                END DO
     208             :             END DO
     209             :          END DO
     210             : 
     211             :       END DO
     212             : 
     213             :       ! Save initialization status
     214             : 
     215        6182 :       current_maxl = maxl
     216             : 
     217        6182 :    END SUBROUTINE create_spherical_harmonics
     218             : 
     219             : ! **************************************************************************************************
     220             : !> \brief   Deallocate the orbital transformation matrices.
     221             : !> \date    20.05.2004
     222             : !> \author  MK
     223             : !> \version 1.0
     224             : ! **************************************************************************************************
     225       14974 :    SUBROUTINE deallocate_spherical_harmonics()
     226             : 
     227             :       INTEGER                                            :: l
     228             : 
     229       14974 : !$    IF (omp_get_level() > 0) &
     230           0 : !$       CPABORT("deallocate_spherical_harmonics is not thread-safe")
     231             : 
     232       14974 :       IF (current_maxl > -1) THEN
     233       39082 :          DO l = 0, SIZE(orbtramat, 1) - 1
     234       32900 :             DEALLOCATE (orbtramat(l)%c2s)
     235       32900 :             DEALLOCATE (orbtramat(l)%s2c)
     236       32900 :             DEALLOCATE (orbtramat(l)%slm)
     237       39082 :             DEALLOCATE (orbtramat(l)%slm_inv)
     238             :          END DO
     239        6182 :          DEALLOCATE (orbtramat)
     240        6182 :          current_maxl = -1
     241             :       END IF
     242             : 
     243       14974 :    END SUBROUTINE deallocate_spherical_harmonics
     244             : 
     245             : ! **************************************************************************************************
     246             : !> \brief  Initialize or update the orbital transformation matrices.
     247             : !> \param maxl ...
     248             : !> \param output_unit ...
     249             : !> \date     09.07.1999
     250             : !> \par Variables
     251             : !>      - maxl   : Maximum angular momentum quantum number
     252             : !> \author MK
     253             : !> \version 1.0
     254             : ! **************************************************************************************************
     255        6619 :    SUBROUTINE init_spherical_harmonics(maxl, output_unit)
     256             : 
     257             :       INTEGER, INTENT(IN)                                :: maxl
     258             :       INTEGER                                            :: output_unit
     259             : 
     260             :       CHARACTER(LEN=78)                                  :: headline
     261             :       INTEGER                                            :: l, nc, ns
     262             : 
     263        6619 : !$    IF (omp_get_level() > 0) &
     264           0 : !$       CPABORT("init_spherical_harmonics is not thread-safe")
     265             : 
     266        6619 :       IF (maxl < 0) THEN
     267             :          CALL cp_abort(__LOCATION__, &
     268             :                        "A negative maximum angular momentum quantum "// &
     269           0 :                        "number is invalid")
     270             :       END IF
     271             : 
     272        6619 :       IF (maxl > current_maxl) THEN
     273             : 
     274        6182 :          CALL deallocate_spherical_harmonics()
     275        6182 :          CALL create_spherical_harmonics(maxl)
     276             : 
     277             :          ! Print the spherical harmonics and the orbital transformation matrices
     278             : 
     279        6182 :          IF (output_unit > 0) THEN
     280             : 
     281           4 :             DO l = 0, maxl
     282             : 
     283           3 :                nc = nco(l)
     284           3 :                ns = nso(l)
     285             : 
     286             :                headline = "CARTESIAN ORBITAL TO SPHERICAL ORBITAL "// &
     287           3 :                           "TRANSFORMATION MATRIX"
     288           3 :                CALL write_matrix(orbtramat(l)%c2s, l, output_unit, headline)
     289             : 
     290             :                headline = "SPHERICAL ORBITAL TO CARTESIAN ORBITAL "// &
     291           3 :                           "TRANSFORMATION MATRIX"
     292           3 :                CALL write_matrix(orbtramat(l)%s2c, l, output_unit, headline)
     293             : 
     294           3 :                headline = "SPHERICAL HARMONICS"
     295           3 :                CALL write_matrix(orbtramat(l)%slm, l, output_unit, headline)
     296             : 
     297           3 :                headline = "INVERSE SPHERICAL HARMONICS"
     298           4 :                CALL write_matrix(orbtramat(l)%slm_inv, l, output_unit, headline)
     299             : 
     300             :             END DO
     301             : 
     302           1 :             WRITE (UNIT=output_unit, FMT="(A)") ""
     303             : 
     304             :          END IF
     305             : 
     306             :       END IF
     307             : 
     308        6619 :    END SUBROUTINE init_spherical_harmonics
     309             : 
     310             : ! **************************************************************************************************
     311             : !> \brief   Print a matrix to the logical unit "lunit".
     312             : !> \param matrix ...
     313             : !> \param l ...
     314             : !> \param lunit ...
     315             : !> \param headline ...
     316             : !> \date    07.06.2000
     317             : !> \par Variables
     318             : !>      - matrix  : Matrix to be printed.
     319             : !>      - l       : Angular momentum quantum number
     320             : !>      - lunit   : Logical unit number.
     321             : !>      - headline: Headline of the matrix.
     322             : !> \author  MK
     323             : !> \version 1.0
     324             : ! **************************************************************************************************
     325          12 :    SUBROUTINE write_matrix(matrix, l, lunit, headline)
     326             : 
     327             :       REAL(KIND=dp), DIMENSION(:, :), INTENT(IN)         :: matrix
     328             :       INTEGER, INTENT(IN)                                :: l, lunit
     329             :       CHARACTER(LEN=*), INTENT(IN)                       :: headline
     330             : 
     331             :       CHARACTER(12)                                      :: symbol
     332             :       CHARACTER(LEN=78)                                  :: string
     333             :       INTEGER                                            :: from, i, ic, is, jc, lx, ly, lz, m, nc, &
     334             :                                                             to
     335             : 
     336             :       ! Write headline
     337             : 
     338          12 :       WRITE (UNIT=lunit, FMT="(/,/,T2,A)") TRIM(headline)
     339             : 
     340             :       ! Write the matrix in the defined format
     341             : 
     342          12 :       nc = nco(l)
     343             : 
     344          28 :       DO ic = 1, nc, 3
     345          16 :          from = ic
     346          16 :          to = MIN(nc, from + 2)
     347          16 :          i = 1
     348          52 :          DO lx = l, 0, -1
     349         116 :             DO ly = l - lx, 0, -1
     350          64 :                lz = l - lx - ly
     351          64 :                jc = co(lx, ly, lz)
     352         100 :                IF ((jc >= from) .AND. (jc <= to)) THEN
     353         160 :                   symbol = cgf_symbol(1, (/lx, ly, lz/))
     354          40 :                   WRITE (UNIT=string(i:), FMT="(A18)") TRIM(symbol(3:12))
     355          40 :                   i = i + 18
     356             :                END IF
     357             :             END DO
     358             :          END DO
     359          16 :          WRITE (UNIT=lunit, FMT="(/,T8,A)") TRIM(string)
     360          16 :          symbol = ""
     361          84 :          DO m = -l, l
     362          56 :             is = l + m + 1
     363          56 :             symbol = sgf_symbol(1, l, m)
     364             :             WRITE (UNIT=lunit, FMT="(T4,A4,3(1X,F17.12))") &
     365          72 :                symbol(3:6), (matrix(is, jc), jc=from, to)
     366             :          END DO
     367             :       END DO
     368             : 
     369          12 :    END SUBROUTINE write_matrix
     370             : 
     371           0 : END MODULE orbital_transformation_matrices

Generated by: LCOV version 1.15