LCOV - code coverage report
Current view: top level - math - ylm4.F90 (source / functions) Hit Total Coverage
Test: FLEUR test coverage Lines: 21 21 100.0 %
Date: 2024-04-24 04:44:14 Functions: 2 2 100.0 %

          Line data    Source code
       1             : MODULE m_ylm
       2             :    use iso_c_binding
       3             :    IMPLICIT NONE
       4             :    PRIVATE
       5             :    PUBLIC ylm4, ylm4_batched
       6             : !************************************************************
       7             : !     generate the spherical harmonics for the vector v
       8             : !     using a stable upward recursion in l.  (see notes
       9             : !     by m. weinert.)
      10             : !          m.weinert   january 1982
      11             : !     modified by R. Podloucky (added in ynorm); July 1989
      12             : !     cleaned up    mw 1995
      13             : !
      14             : !     modified to make use of f90 constructs. note that
      15             : !     the normalization is an internal subroutine and hence
      16             : !     can only be called from here. also, no need to dimension
      17             : !     arrays for ynorm, done dynamically.          mw 1999
      18             : !
      19             : !     GPU version added
      20             : !             U.Alekseeva      Oktober 2018
      21             : !************************************************************
      22             : CONTAINS
      23    21359881 :    SUBROUTINE ylm4(lmax, v, ylm)
      24             : !      USE m_juDFT
      25             :       INTEGER, VALUE, INTENT(IN)   :: lmax
      26             :       REAL, INTENT(IN), target     :: v(3)
      27             :       COMPLEX, INTENT(OUT), target :: ylm((lmax + 1)**2)
      28             : 
      29             :       real, pointer    :: v_2d(:,:)
      30    21359881 :       complex, pointer :: ylm_2d(:,:)
      31             : 
      32    64079643 :       call c_f_pointer(c_loc(v),   v_2d,   [3,1])
      33    64079643 :       call c_f_pointer(c_loc(ylm), ylm_2d, [(lmax + 1)**2, 1])
      34    21359881 :       call ylm4_batched(lmax, v_2d, ylm_2d)
      35    21359881 :    END SUBROUTINE ylm4
      36             : 
      37    21409490 :    subroutine ylm4_batched(lmax, v, ylm)
      38             :       implicit none
      39             :       INTEGER, VALUE, INTENT(IN) :: lmax
      40             :       REAL, INTENT(IN) :: v(:,:)
      41             :       COMPLEX, INTENT(OUT):: ylm(:,:)
      42             : 
      43             :       INTEGER  :: l, lm0, m, i
      44             :       REAL     :: fac, x, y, z, xy, r, rxy, cth, sth, cph, sph, cph2
      45    21409490 :       REAL     :: c(0:max(lmax,1)), s(0:max(lmax,1))
      46    21409490 :       REAL     :: p(0:lmax, 0:lmax)
      47             :       COMPLEX  :: ylms
      48    21409490 :       REAL     :: ynorm_dev((lmax + 1)**2)
      49             :       REAL     :: a, cd
      50             :       real, parameter :: fpi = 4.0*3.1415926535897932, small = 1.0e-12
      51             : 
      52             :       !--->    calculate norm
      53   168436220 :       DO l = 0, lmax
      54   147026730 :          lm0 = l*(l + 1) + 1
      55   147026730 :          cd = 1.0
      56   147026730 :          a = sqrt((2*l + 1)/fpi)
      57   147026730 :          ynorm_dev(lm0) = a
      58   756959171 :          DO m = 1, l
      59   588522951 :             cd = cd/((l + 1 - m)*(l + m))
      60   588522951 :             ynorm_dev(lm0 + m) = a*sqrt(cd)
      61   735549681 :             ynorm_dev(lm0 - m) = ((-1.0)**m)*ynorm_dev(lm0 + m)
      62             :          ENDDO
      63             :       ENDDO
      64             : 
      65             : 
      66             : !--->    calculate sin and cos of theta and phi
      67             :       !$OMP parallel do default(none) &
      68             :       !$OMP private(i, x, y, z, xy, r, rxy, cth, sth, fac, m, l, p, c ,s, ylms, lm0, cph, sph, cph2)&
      69    21409490 :       !$OMP shared(ylm, ynorm_dev, lmax, v)
      70             :       do i = 1,size(v,2)
      71             :          x = v(1,i)
      72             :          y = v(2,i)
      73             :          z = v(3,i)
      74             :          xy = x*x + y*y
      75             :          r = sqrt(xy + z*z)
      76             :          rxy = sqrt(xy)
      77             : 
      78             :          IF (r .GT. small) THEN
      79             :             cth = z/r
      80             :             sth = rxy/r
      81             :          ELSE
      82             :             sth = 0.0
      83             :             cth = 1.0
      84             :          ENDIF
      85             :          IF (rxy .GT. small) THEN
      86             :             cph = x/rxy
      87             :             sph = y/rxy
      88             :          ELSE
      89             :             cph = 1.0
      90             :             sph = 0.0
      91             :          ENDIF
      92             : 
      93             :    !---> generate associated legendre functions for m.ge.0
      94             :          fac = 1.0
      95             :    !---> loop over m values
      96             :          DO m = 0, lmax - 1
      97             :             fac = -(m + m - 1)*fac
      98             :             p(m, m) = fac
      99             :             p(m + 1, m) = (m + m + 1)*cth*fac
     100             :    !--->    recurse upward in l
     101             :             DO l = m + 2, lmax
     102             :                p(l, m) = ((l + l - 1)*cth*p(l - 1, m) - (l + m - 1)*p(l - 2, m))/(l - m)
     103             :             ENDDO
     104             :             fac = fac*sth
     105             :          ENDDO
     106             :          p(lmax, lmax) = -(lmax + lmax - 1)*fac
     107             : 
     108             :    !--->    determine sin and cos of phi
     109             :          s(0) = 0.0
     110             :          s(1) = sph
     111             :          c(0) = 1.0
     112             :          c(1) = cph
     113             :          cph2 = cph + cph
     114             :          DO m = 2, lmax
     115             :             s(m) = cph2*s(m - 1) - s(m - 2)
     116             :             c(m) = cph2*c(m - 1) - c(m - 2)
     117             :          ENDDO
     118             : 
     119             :    !--->    multiply in the normalization factors
     120             :          DO l = 0, lmax
     121             :             ylm(l*(l + 1) + 1, i) = ynorm_dev(l*(l + 1) + 1)*cmplx(p(l, 0), 0.0)
     122             :          ENDDO
     123             :          DO m = 1, lmax
     124             :             DO l = m, lmax
     125             :                lm0 = l*(l + 1) + 1
     126             :                ylms = p(l, m)*cmplx(c(m), s(m))
     127             :                ylm(lm0 + m, i) = ynorm_dev(lm0 + m)*ylms
     128             :                ylm(lm0 - m, i) = conjg(ylms)*ynorm_dev(lm0 - m)
     129             :             ENDDO
     130             :          ENDDO
     131             :       enddo
     132             :       !$OMP end parallel do
     133    21409490 :    end subroutine ylm4_batched
     134             : END MODULE m_ylm

Generated by: LCOV version 1.14