sphere_gga.f90 Source File


Source Code

!-----------------------------------------------------------------------------------------!
! Copyright (c) 2018 Peter Grünberg Institut, Forschungszentrum Jülich, Germany           !
! This file is part of Jülich KKR code and available as free software under the conditions!
! of the MIT license as expressed in the LICENSE.md file in more detail.                  !
!-----------------------------------------------------------------------------------------!

!------------------------------------------------------------------------------------
!> Summary: Generate an angular mesh and spherical harmonics for the treatement of the GGA xc-potential
!> Author: R. Zeller, Phivos Mavropoulos
!> Generate an angular mesh and spherical harmonics for the treatement of the GGA 
!> xc-potential. For an angular integration the weights are also generated.
!------------------------------------------------------------------------------------
module mod_sphere_gga
  use :: mod_datatypes, only: dp
  private :: dp

contains

  !-------------------------------------------------------------------------------
  !> Summary: Generate an angular mesh and spherical harmonics at those mesh points.
  !> Author: R. Zeller
  !> Category: xc-potential, special-functions, KKRhost
  !> Deprecated: False 
  !> Generate an angular mesh and spherical harmonics at those mesh points. For an 
  !> angular integration the weights are also generated. This is needed for the 
  !> calculation of the GGA exchange correlation potentials.
  !-------------------------------------------------------------------------------
  !> @note Phivos Mavropoulos, July 2007: New call to subroutine `ylmderiv` for
  !> accurate derivatives of spherical harmonics.
  !> @endnote
  !-------------------------------------------------------------------------------
  subroutine sphere_gga(lmax,yr,wtyr,rij,ijd,lmmaxd,thet,ylm,dylmt1,dylmt2,dylmf1,  &
    dylmf2,dylmtf)

    use :: mod_datatypes, only: dp
    use :: mod_lebedev, only: lebedev
    use :: mod_ymy, only: ymy
    use :: mod_constants, only: pi
    implicit none

    ! .. Scalar Arguments ..
    integer :: ijd, lmax, lmmaxd
    ! ..
    ! .. Local Scalars ..
    real (kind=dp) :: r, r1, r2, r3
    integer :: ij, lm1
    ! ..
    ! .. Array Arguments ..
    real (kind=dp) :: dylmf1(ijd, lmmaxd), dylmf2(ijd, lmmaxd), dylmt1(ijd, lmmaxd)
    real (kind=dp) :: dylmt2(ijd, lmmaxd), dylmtf(ijd, lmmaxd), rij(ijd, 3), thet(ijd)
    real (kind=dp) :: wtyr(ijd, *), ylm(ijd, lmmaxd), yr(ijd, *), dydth(lmmaxd)
    real (kind=dp) :: dydfi(lmmaxd), d2ydth2(lmmaxd), d2ydfi2(lmmaxd), d2ydthdfi(lmmaxd)
    ! ..
    ! .. Local Arrays ..
    real (kind=dp) :: wght, y(1000)
    ! ..
    write (1337, *) 'SPHERE for GGA: read LEBEDEV mesh'
    if (ijd>1000) stop 'SPHERE'


    do ij = 1, ijd
      call lebedev(ij, r1, r2, r3, wght)
      rij(ij, 1) = r1
      rij(ij, 2) = r2
      rij(ij, 3) = r3

      ! For the needs of GGA PW91 as implemented here, ylm and derivatives
      ! come with a different sign convention compared to the usual in the
      ! program: sin(fi)**m --> -sin(fi)**m. Thus some signs change
      ! also in array ylm compared to array yr (below).
      call derivylm(r1, r2, r3, lmax, r, y, dydth, dydfi, d2ydth2, d2ydfi2, d2ydthdfi)

      thet(ij) = acos(r3/r)

      do lm1 = 1, (lmax+1)**2
        ylm(ij, lm1) = y(lm1)
        dylmt1(ij, lm1) = dydth(lm1)
        dylmf1(ij, lm1) = dydfi(lm1)
        dylmt2(ij, lm1) = d2ydth2(lm1)
        dylmf2(ij, lm1) = d2ydfi2(lm1)
        dylmtf(ij, lm1) = d2ydthdfi(lm1)
      end do

      ! Call ymy to obtain sher. harmonics with usual convention
      ! ---> multiply the spherical harmonics with the weights
      call ymy(r1, r2, r3, r, y, lmax)
      do lm1 = 1, (lmax+1)**2
        yr(ij, lm1) = y(lm1)
        wtyr(ij, lm1) = yr(ij, lm1)*wght*pi*4.e0_dp
      end do
    end do

  end subroutine sphere_gga

  !-------------------------------------------------------------------------------
  !> Summary: Calculate the 1st and 2nd derivatives of real spherical harmonics with respect to \(\theta\), \(\phi\)
  !> Author: Ph.Mavropoulos
  !> Category: xc-potential, special-functions, KKRhost
  !> Deprecated: False 
  !> Calculate the 1st and 2nd derivatives of real spherical harmonics
  !> with respect to \(\theta\), \(\phi\).
  !> Use recursion relations for the assoc. Legendre functions \(P[l,m]\) to generate
  !> the derivatives. These are (taken from Abramowitz and Stegun, Handbook of 
  !> Mathematical Functions, chapt. 8.):
  !> \begin{equation}
  !> P[l,m+1] = (x^2-1)^{-\frac{1}{2}} ( (l-m)xP[l,m] - (l+m)P[l-1,m] )
  !> \end{equation}
  !> \begin{equation}
  !> (x^2-1)\frac{d}{dx}P[l,m] = (l+m)(l-m+1)(x^2-1)^\frac{1}{2} P[l,m-1] - mxP[l,m]
  !> \end{equation}
  !> \begin{equation}
  !> (x^2-1)\frac{d}{dx}P[l,m] = lxP[l,m] - (l+m)P[l-1,m] 
  !> \end{equation}
  !> where \(x=\cos{\theta}\), \((x^2-1)^\frac{1}{2} = -\sin{\theta}\), \(\frac{d}{d\theta} = -\sin{\theta} \frac{d}{dx}\)
  !> Adding these equations:
  !> \begin{equation}
  !> \frac{d}{d\theta}P[l,m](\cos{\theta}) = \frac{1}{2} ( -(l+m)(l-m+1)P[l,m-1] + P[l,m+1] )
  !> \end{equation}
  !> It is implied that \(P[l,m]=0\) if \(m>l\) or \(m<-l\). Also, the term \((x^2-1)^\frac{1}{2}\)
  !> is ambiguous for real \(x\), \(0<x<1\); here it is interpreted as
  !> \begin{equation}
  !> (x^2-1)^\frac{1}{2}=-\sin{\theta} 
  !> \end{equation}
  !> but
  !> \begin{equation}
  !> (x^2-1)^{-\frac{1}{2}}=\frac{1}{\sin{\theta}}
  !> \end{equation}
  !> otherwise the result from Eq.4 (which is cross-checked and correct) does not follow.
  !> For the 2nd derivative apply Eq.4 twice. Result:
  !> \begin{equation}
  !> \begin{split}
  !> \frac{d^2}{d\theta^2}P[l,m](\cos{\theta}) = \frac{1}{4}((l+m)(l-m+1)(l+m-1)(l-m+2) P[l,m-2]&\\-((l-m)(l+m+1)+(l+m)(l-m+1) )P[l,m]+ P[l,m+2])
  !> \end{split}
  !> \end{equation}
  !> The \(\phi\)-derivatives act on \cos{\phi},\sin{\phi} and are trivial.
  !> For the associated Legendre functions use the recursion formulas:
  !> \begin{equation}
  !> (l-m+1)P[l+1,m] = (2l+1)\cos{\theta}P[l,m] - (l+m)P[l-1,m] 
  !> \end{equation}
  !> \begin{equation}
  !> P[l+1,m] = P[l-1,m] - (2*l+1)\sin{\theta}P[l,m-1] 
  !> \end{equation}
  !> ( with \(x=\cos{\theta} \).
  !> Recursion algorithm for the calculation of \(P[l,m]\) and calculation of \(Y_l^m\)
  !> taken over from subr. `ymy` of KKR program (implemented there by M. Weinert, B. Drittler).
  !> For \(m<0\), use 
  !> \begin{equation}
  !> P[l,-m] = P[l,m] \frac{(l-m)!}{(l+m)!}
  !> \end{equation}
  !> Taking into account the lm-prefactors of the spherical harmonics, we construct 
  !> and use the functions
  !> \begin{equation}
  !> Q[l,m] = \sqrt{\frac{2l+1}{4\pi}} \sqrt{\frac{(l-m)!}{(l+m)!}} P[l,m]
  !> \end{equation}
  !> whence Eq.4 and Eq.7 become
  !> \begin{equation}
  !> \frac{d}{d\theta}Q[l,m]= \frac{1}{2}(-\sqrt{(l+m)(l-m+1)}Q[l,m-1]+ \sqrt{(l+m+1)(l-m)}Q[l,m+1] )
  !> \end{equation}
  !> \begin{equation}
  !> \begin{split}
  !> \frac{d^2}{d\theta^2}Q[l,m] = \frac{1}{4}(\sqrt{(l+m)(l+m-1)(l-m+1)(l-m+2)} Q[l,m-2]&\\+((l-m)(l+m+1)+(l+m)(l-m+1)) Q[l,m]&\\+ \sqrt{(l-m)(l-m-1)(l+m+1)(l+m+2)} Q[l,m+2])
  !> \end{split}
  !> \end{equation}
  !> Note on sign convension:
  !> For the needs of GGA PW91 as implemented here, ylm and derivatives
  !> come with a different sign convention compared to the usual in the
  !> program: \(\sin{\phi}^m \rightarrow (-1)^m \sin{\phi}^m\). Thus some signs change.  
  !-------------------------------------------------------------------------------
  subroutine derivylm(v1, v2, v3, lmax, rabs, ylm, dydth, dydfi, d2ydth2, d2ydfi2, d2ydthdfi)

    use :: mod_datatypes, only: dp
    use :: mod_rinit, only: rinit
    use :: mod_constants, only: pi
    implicit none
    ! Parameters:
    integer :: lmaxd, l4maxd
    parameter (lmaxd=4, l4maxd=4*lmaxd)
    ! Input:
    integer :: lmax                ! up to which l to calculate
    real (kind=dp) :: v1, v2, v3   ! vector where Ylm etc are calculated (not
    ! necessarily normalized)
    ! Output:
    ! Y[l,m], dY/dth, dY/dfi, d(dY/dth)/dth, d(dY/dfi)/dfi, d(dY/dth)/dfi
    real (kind=dp) :: ylm(*), dydth(*), dydfi(*), d2ydth2(*), d2ydfi2(*), d2ydthdfi(*)
    real (kind=dp) :: rabs         ! Norm of input vector (V1,V2,V3)
    ! Inside:
    real (kind=dp) :: cth, sth, cfi, sfi ! cos and sin of th and fi
    real (kind=dp) :: fpi, rtwo ! pi (what else?), 4*pi, sqrt(2)
    real (kind=dp) :: fac          ! factor in construction of polynomials.
    real (kind=dp) :: plm(0:l4maxd, 0:l4maxd) ! Legendre polynomials
    real (kind=dp) :: qlm((l4maxd+1)**2) ! Ylm/cos(m*fi) (m>0) and Ylm/sin(m*fi)
    ! (m<0)
    real (kind=dp) :: cmfi(0:l4maxd), smfi(0:l4maxd) ! cos(m*fi) and sin(m*fi)
    real (kind=dp) :: xy, xyz, sgm, sgmm
    real (kind=dp) :: aux
    real (kind=dp) :: tiny
    parameter (tiny=1.e-20_dp)     ! if th < tiny set th=0
    real (kind=dp) :: tt, aa, cd   ! factors in calcul. of Ylm
    integer :: ll, mm, ii          ! l and m indexes
    integer :: lmmax0d             ! (lmax+1)**2, total number of spher.
    ! harmonics.
    integer :: imm, ipm, lpm, lmm, lpmp1, lmmp1 ! i-m,i+m,l+m,l-m,l+m+1,l-m-1

    fpi = 4.e0_dp*pi
    rtwo = sqrt(2.e0_dp)
    lmmax0d = (lmax+1)**2

    if (lmax>l4maxd) stop 'derivylm: lmax out of range.'

    ! --->    calculate sin and cos of theta and phi
    xy = v1**2 + v2**2
    xyz = xy + v3**2

    rabs = sqrt(xyz)
    if (xyz<=0.0e0_dp) stop 'derivylm: v=0.'

    if (xy>tiny*xyz) then
      xy = sqrt(xy)
      xyz = sqrt(xyz)
      cth = v3/xyz
      sth = xy/xyz
      cfi = v1/xy
      sfi = v2/xy

    else

      sth = 0.0e0_dp
      cth = 1.0e0_dp
      if (v3<0) cth = -1.0e0_dp
      cfi = 1.0e0_dp
      sfi = 0.0e0_dp
    end if

    ! First calculate Legendre functions. Use recursion formulas (8.5.3,8.5.5).
    ! Following taken from KKR program (routine ymy, by M.Weinert).
    fac = 1.0e0_dp
    do mm = 0, lmax - 1
      fac = -real(2*mm-1, kind=dp)*fac
      plm(mm, mm) = fac
      plm(mm+1, mm) = real(2*mm+1, kind=dp)*cth*fac

      ! --->    recurse upward in l
      do ll = mm + 2, lmax
        plm(ll, mm) = (real(2*ll-1,kind=dp)*cth*plm(ll-1,mm)-real(ll+mm-1,kind=dp)*plm(ll-2,mm))/real(ll-mm, kind=dp)
      end do
      fac = fac*sth
    end do
    plm(lmax, lmax) = -(2*lmax-1)*fac

    ! Next calculate Ylm and derivatives.
    ! --->    determine powers of sin and cos of phi
    smfi(0) = 0.0e0_dp
    smfi(1) = sfi
    cmfi(0) = 1.0e0_dp
    cmfi(1) = cfi
    do mm = 2, lmax
      smfi(mm) = 2.e0_dp*cfi*smfi(mm-1) - smfi(mm-2)
      cmfi(mm) = 2.e0_dp*cfi*cmfi(mm-1) - cmfi(mm-2)
    end do

    ! For the needs of GGA PW91 as implemented here, ylm and derivatives
    ! come with a different sign convention compared to the usual in the
    ! program: sin(fi)**m --> (-1)**m * sin(fi)**m. Thus some signs change.
    ! This is taken care of here:
    !fi = atan2(v2, v1)
    ! THE CHANGE OF SIGN BELOW IS WRONG AND THEREFORE NOT DONE ANYMORE
    ! It was introduced to keep results consistent with older versions which
    ! already yielded wrong results
    ! if (fi.lt.0.d0) then
    ! do mm = 1,lmax
    ! smfi(mm) = -smfi(mm)
    ! enddo
    ! endif
    ! --->    multiply in the normalization factors;
    ! calculate Ylm and derivatives with respect to fi.
    ii = 0
    do ll = 0, lmax
      ii = ii + ll + 1
      aa = sqrt(real(2*ll+1,kind=dp)/fpi)
      cd = 1.e0_dp
      ylm(ii) = aa*plm(ll, 0)
      dydfi(ii) = 0.e0_dp
      d2ydfi2(ii) = 0.e0_dp

      qlm(ii) = rtwo*aa*plm(ll, 0)
      sgm = -rtwo                  ! updated to (-1)**m * rtwo
      sgmm = -1                    ! updated to (-1)**m
      do mm = 1, ll
        ipm = ii + mm
        imm = ii - mm
        tt = real((ll+1-mm)*(ll+mm), kind=dp)
        cd = cd/tt
        tt = aa*sqrt(cd)

        qlm(ipm) = sgm*tt*plm(ll, mm)
        qlm(imm) = sgmm*qlm(ipm)

        ylm(ipm) = qlm(ipm)*cmfi(mm)
        ylm(imm) = sgmm*qlm(imm)*smfi(mm)

        dydfi(ipm) = -real(mm, kind=dp)*ylm(imm)
        dydfi(imm) = real(mm, kind=dp)*ylm(ipm)
        d2ydfi2(ipm) = -real(mm*mm, kind=dp)*ylm(ipm)
        d2ydfi2(imm) = -real(mm*mm, kind=dp)*ylm(imm)

        sgm = -sgm
        sgmm = -sgmm

      end do
      ii = ii + ll
    end do

    ! Derivatives with respect to th
    call rinit(lmmax0d, dydth)
    call rinit(lmmax0d, d2ydth2)
    call rinit(lmmax0d, d2ydthdfi)
    ! The l=0 derivatives are zero (established by initialization above).
    ! Start with l=1.
    do ll = 1, lmax
      ii = ll*(ll+1) + 1           ! (position of m=0 harmonic in array)
      aa = real(ll*(ll+1), kind=dp)
      ! Take special care of m=0 harmonic due to 1/sqrt(2)
      dydth(ii) = -sqrt(aa)*qlm(ii+1)/rtwo
      aux = -2.e0_dp*aa*qlm(ii)
      if (ll>1) aux = aux + (qlm(ii-2)+qlm(ii+2))*sqrt(real((ll-1)*ll*(ll+1)*(ll+2),kind=dp))
      d2ydth2(ii) = 0.25e0_dp*aux/rtwo

      do mm = 1, ll
        ipm = ii + mm
        imm = ii - mm

        lpm = ll + mm
        lmm = ll - mm
        lpmp1 = ll + mm + 1
        lmmp1 = ll - mm + 1
        ! Apply Eq. (A1)
        aux = qlm(ipm-1)*sqrt(real(lpm*lmmp1,kind=dp))
        if (mm<ll) aux = aux - qlm(ipm+1)*sqrt(real(lpmp1*lmm,kind=dp))
        aux = 0.5e0_dp*aux

        dydth(ipm) = aux*cmfi(mm)
        dydth(imm) = aux*smfi(mm)

        d2ydthdfi(ipm) = -real(mm, kind=dp)*aux*smfi(mm)
        d2ydthdfi(imm) = real(mm, kind=dp)*aux*cmfi(mm)

        ! Apply Eq. (B1)
        aux = -qlm(ipm)*real(lmm*lpmp1+lpm*lmmp1, kind=dp)
        if (mm<ll-1) aux = aux + qlm(ipm+2)*sqrt(real((lmm-1)*lmm*lpmp1*(lpm+2),kind=dp))
        aux = aux + qlm(ipm-2)*sqrt(real(lmmp1*(lmm+2)*(lpm-1)*lpm,kind=dp))
        aux = 0.25e0_dp*aux

        d2ydth2(ipm) = aux*cmfi(mm)
        d2ydth2(imm) = aux*smfi(mm)

      end do
    end do

  end subroutine derivylm

end module mod_sphere_gga