sphere_gga.f Source File


Source Code

  !-------------------------------------------------------------------------------
  !> Summary: Generate an angular mesh and spherical harmonics at those mesh points. For an angular integration the weights are generated .
  !> Author: R. Zeller, Phivos Mavropoulos
  !> Date: February 1996, July 2007
  !> Category: special-functions, radial-grid, KKRimp
  !> Deprecated: False 
  !> Generate an angular mesh and spherical harmonics at those
  !> mesh points. For an angular integration the weights are generated  
  !>
  !> New call to subr. ylmderiv for accurate derivatives of
  !> spherical harmonics.
  !-------------------------------------------------------------------------------
      SUBROUTINE SPHERE_GGA(LMAX,YR,WTYR,RIJ,IJD,LMMAXD,THET,YLM,
     +                      DYLMT1,DYLMT2,DYLMF1,DYLMF2,DYLMTF)
      USE MOD_YMY
      use mod_types, only: t_inc
      IMPLICIT NONE

C     .. Scalar Arguments ..
      INTEGER IJD,LMAX,LMMAXD
C     ..
C     .. Local Scalars ..
      DOUBLE PRECISION PI,R,R1,R2,R3
      INTEGER IJ,LM1
C     ..
C     .. External Subroutines ..
!       EXTERNAL CYLM02,YMY
C     ..
C     .. Array Arguments ..
      DOUBLE PRECISION DYLMF1(IJD,LMMAXD),DYLMF2(IJD,LMMAXD),
     +                 DYLMT1(IJD,LMMAXD),DYLMT2(IJD,LMMAXD),
     +                 DYLMTF(IJD,LMMAXD),RIJ(IJD,3),THET(IJD),
     +      WTYR(IJD,(LMAX+1)**2),YLM(IJD,LMMAXD),YR(IJD,(LMAX+1)**2)
     &                ,DYDTH(LMMAXD),DYDFI(LMMAXD),D2YDTH2(LMMAXD)
     &                ,D2YDFI2(LMMAXD),D2YDTHDFI(LMMAXD)
C     ..
C     .. Local Arrays ..
C
      DOUBLE PRECISION WGHT,Y(1000)
C     ..
C     .. Intrinsic Functions ..
      INTRINSIC ABS,ACOS,ATAN,COS,SIN,SQRT
C     ..
      PI = 4.D0*ATAN(1.D0)
      if (t_inc%i_write>0) WRITE (1337,*) 
     &              'SPHERE for GGA: read LEBEDEV mesh'
      IF (IJD.GT.1000) STOP 'SPHERE'
c
c
      DO 30 IJ = 1,IJD
         CALL LEBEDEV (IJ,R1,R2,R3,WGHT)
         RIJ(IJ,1) = R1
         RIJ(IJ,2) = R2
         RIJ(IJ,3) = R3


C
c For the needs of GGA PW91 as implemented here, ylm and derivatives
c come with a different sign convention compared to the usual in the
c program: sin(fi)**m --> -sin(fi)**m. Thus some signs change
c also in array ylm compared to array yr (below).
         CALL DERIVYLM(
     >        R1,R2,R3,LMAX,
     <        R,Y,DYDTH,DYDFI,D2YDTH2,D2YDFI2,D2YDTHDFI)

         THET(IJ) = DACOS(R3/R)


         DO 10 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)
 10      CONTINUE

c Call ymy to obtain sher. harmonics with usual convention
c
c---> multiply the spherical harmonics with the weights
c

         CALL YMY(R1,R2,R3,R,Y,LMAX)
         DO 20 LM1 = 1, (LMAX+1)**2
            YR(IJ,LM1) = Y(LM1)
            WTYR(IJ,LM1) = YR(IJ,LM1)*WGHT*PI*4.D0
 20      CONTINUE




   30 CONTINUE


      END SUBROUTINE


  !-------------------------------------------------------------------------------
  !> Summary: Generate an angular mesh and spherical harmonics at those mesh points. For an angular integration the weights are generated .
  !> Author: Ph.Mavropoulos
  !> Date: July 2007
  !> Category: special-functions, numerical-tools, KKRimp
  !> 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.):
  !>
  !> P[l,m+1] = (x^2-1)^(-1/2) ( (l-m)*x*P[l,m] - (l+m)*P[l-1,m] ) (8.5.1)
  !>
  !> (x^2-1)*dP[l,m]/dx = (l+m)*(l-m+1)*(x^2-1)^(1/2) P[l,m-1] - m*x*P[l,m]  (8.5.2)
  !>
  !> (x^2-1)*dP[l,m]/dx = l*x*P[l,m] - (l+m)*P[l-1,m]           (8.5.4)
  !>
  !> where x=cos(th), (x^2-1)^(1/2) = -sin(th), d/dth = -sin(th) d/dx.
  !>
  !> Adding (8.5.2)+(8.5.4) and using (8.5.1) results in:
  !>
  !> dP[l,m](cos(th)) / dth = (1/2) * ( -(l+m)*(l-m+1)*P[l,m-1] + P[l,m+1] )   (A)
  !>
  !>
  !> It is implied that P[l,m]=0 if m>l or m<-l. Also, the term (x^2-1)^(1/2)
  !> is ambiguous for real x, 0<x<1; here it is interpreted as 
  !> (x^2-1)^(1/2)=-sin(th), but (x^2-1)^(-1/2)=+1/sin(th) (in 8.5.1), 
  !> otherwise the result (A) (which is cross-checked and correct) does not follow.
  !>
  !> For the 2nd derivative apply (A) twice. Result:
  !>
  !> ddP[l,m](cos(th))/dth/dth = (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]  )   (B)
  !>
  !> The fi-derivatives act on cos(fi),sin(fi) and are trivial.
  !>
  !> For the associated Legendre functions use the recursion formulas:
  !>
  !> (l-m+1)*P[l+1,m] = (2l+1)*cos(th)*P[l,m] - (l+m)*P[l-1,m]   (8.5.3)
  !>
  !> P[l+1,m] = P[l-1,m] - (2*l+1)*sin(th)*P[l,m-1]              (8.5.5)
  !>
  !> ( with x=cos(th) ).
  !>
  !> Recursion algorithm for the calculation of P[l,m] and calculation of Ylm 
  !> taken over from subr. ymy of KKR program 
  !> (implemented there by M. Weinert, B. Drittler).
  !>
  !> For m<0, use P[l,-m] = P[l,m] (l-m)!/(l+m)!     (C)
  !>
  !> Taking into account the lm-prefactors of the spherical harmonics, 
  !> we construct and use the functions
  !> 
  !> Q[l,m] = sqrt((2*l+1)/(4*pi)) * sqrt((l-m)!/(l+m)!) * P[l,m]
  !>
  !> whence (A) and (B) become
  !>
  !> dQ[l,m]/dth = (1/2) *
  !>     ( -sqrt((l+m)*(l-m+1))*Q[l,m-1] + sqrt((l+m+1)*(l-m))*Q[l,m+1] )   (A1)
  !>
  !> ddQ[l,m]/dth/dth = (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]      )      (A2)
  !>
  !>
  !> 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)
      implicit none
c Parameters:
      integer lmaxd,l4maxd
      parameter (lmaxd=4,l4maxd=4*lmaxd)
c Input:
      integer lmax  ! up to which l to calculate
      real*8 v1,v2,v3 ! vector where Ylm etc are calculated (not necessarily normalized)
c Output:
c Y[l,m], dY/dth, dY/dfi, d(dY/dth)/dth, d(dY/dfi)/dfi, d(dY/dth)/dfi
      real*8 Ylm(*),dYdth(*),dYdfi(*),d2Ydth2(*),d2Ydfi2(*),d2Ydthdfi(*)
      real*8 Rabs  ! Norm of input vector (V1,V2,V3)
c Inside:
      real*8 cth,sth,cfi,sfi  ! cos and sin of th and fi
      real*8 pi,fpi,rtwo   ! pi (what else?), 4*pi, sqrt(2)
      real*8 fac      ! factor in construction of polynomials.
      real*8 Plm(0:l4maxd,0:l4maxd)  ! Legendre polynomials
      real*8 Qlm((l4maxd+1)**2)      ! Ylm/cos(m*fi) (m>0) and Ylm/sin(m*fi) (m<0)
      real*8 cmfi(0:l4maxd),smfi(0:l4maxd) ! cos(m*fi) and sin(m*fi)
      real*8 xy,xyz,sgm,sgmm,fi
      real*8 aux
      real*8 tiny
      parameter(tiny=1.d-20)  ! if th < tiny set th=0
      real*8 tt,aa,cd  ! factors in calcul. of Ylm
      integer ll,mm,ii   ! l and m indexes
      integer lmmax      ! (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

      pi = 4.d0*datan(1.d0)
      fpi = 4.d0*pi
      rtwo = dsqrt(2.d0)
      lmmax = (lmax+1)**2

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

c
c--->    calculate sin and cos of theta and phi
c
      xy = v1**2 + v2**2
      xyz = xy + v3**2
c
      Rabs = dsqrt(xyz)
      if (xyz.le.0.0d0) stop 'derivylm: v=0.'

      if (xy.gt.tiny*xyz) then
         xy = dsqrt(xy)
         xyz = dsqrt(xyz)
         cth = v3/xyz
         sth = xy/xyz
         cfi = v1/xy
         sfi = v2/xy

      else
           
         sth = 0.0d0
         cth = 1.0d0
         if (v3.lt.0) cth = -1.0d0
         cfi = 1.0d0
         sfi = 0.0d0
      end if

c First calculate Legendre functions. Use recursion formulas (8.5.3,8.5.5).
c Following taken from KKR program (routine ymy, by M.Weinert).
      fac = 1.0d0
      do 20 mm = 0,lmax - 1
         fac = - dfloat(2*mm-1) * fac
         Plm(mm,mm) = fac
         Plm(mm+1,mm) = dfloat(2*mm+1) * cth * fac
c
c--->    recurse upward in l
c
         do 10 ll = mm + 2,lmax
            Plm(ll,mm) 
     &      = (   dfloat(2*ll-1) * cth * Plm(ll-1,mm)
     &          - dfloat(ll+mm-1) * Plm(ll-2,mm)       ) / dfloat(ll-mm)
 10      continue
         fac = fac*sth
 20   continue
      Plm(lmax,lmax) = - (2*lmax - 1) * fac


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

c For the needs of GGA PW91 as implemented here, ylm and derivatives
c come with a different sign convention compared to the usual in the
c program: sin(fi)**m --> (-1)**m * sin(fi)**m. Thus some signs change.
c This is taken care of here:
      fi = datan2(v2,v1)
      if (fi.lt.0.d0) then
         do mm = 1,lmax
            smfi(mm) = -smfi(mm) 
         enddo
      endif
c
c
c
c--->    multiply in the normalization factors;
c        calculate Ylm and derivatives with respect to fi.
c
      ii = 0
      do 50 ll = 0,lmax
         ii = ii + ll + 1
         aa = dsqrt(dfloat(2*ll+1)/fpi)
         cd = 1.d0
         Ylm(ii) = aa * Plm(ll,0)
         dYdfi(ii) = 0.d0
         d2Ydfi2(ii) = 0.d0

         Qlm(ii) = rtwo * aa * Plm(ll,0)


         sgm = -rtwo   ! updated to (-1)**m * rtwo
         sgmm = -1     ! updated to (-1)**m
         do 40 mm = 1,ll
            ipm = ii + mm
            imm = ii - mm
            tt = dfloat((ll+1-mm)*(ll+mm))
            cd = cd / tt
            tt = aa * dsqrt(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) = -dfloat(mm) *  Ylm(imm)
            dYdfi(imm) =  dfloat(mm) *  Ylm(ipm)
            d2Ydfi2(ipm) = -dfloat(mm*mm) * Ylm(ipm)
            d2Ydfi2(imm) = -dfloat(mm*mm) * Ylm(imm)

            sgm = -sgm
            sgmm = -sgmm

 40      continue
         ii = ii + ll
 50   continue


c Derivatives with respect to th
      call rinit(lmmax,dYdth)
      call rinit(lmmax,d2Ydth2)
      call rinit(lmmax,d2Ydthdfi)
c The l=0 derivatives are zero (established by initialization above).
c Start with l=1.      
      do 70 ll = 1,lmax
         ii = ll*(ll+1) + 1       ! (position of m=0 harmonic in array)
         aa = dfloat(ll*(ll+1))

c Take special care of m=0 harmonic due to 1/sqrt(2)
         dYdth(ii) = -dsqrt(aa) * Qlm(ii+1) / rtwo

         aux = -2.d0 * aa * Qlm(ii)
         if (ll.gt.1) aux = aux + 
     &    (Qlm(ii-2)+Qlm(ii+2)) * dsqrt(dfloat((ll-1)*ll*(ll+1)*(ll+2)))
         d2Ydth2(ii) = 0.25d0 * aux / rtwo
         
         do 60 mm = 1,ll
            ipm = ii + mm
            imm = ii - mm

            lpm = ll + mm
            lmm = ll - mm
            lpmp1 = ll + mm + 1
            lmmp1 = ll - mm + 1
c Apply Eq. (A1)            
            aux = Qlm(ipm-1) * dsqrt(dfloat(lpm*lmmp1))  
            if (mm.lt.ll) 
     &      aux = aux - Qlm(ipm+1) * dsqrt(dfloat(lpmp1*lmm))
            aux = 0.5d0 * aux

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

            d2Ydthdfi(ipm) = -dfloat(mm) * aux * smfi(mm)
            d2Ydthdfi(imm) =  dfloat(mm) * aux * cmfi(mm)

c Apply Eq. (B1)
            aux = -Qlm(ipm) 
     &       * dfloat( lmm*lpmp1 + lpm*lmmp1 )
            if (mm.lt.ll-1) aux = aux + Qlm(ipm+2) 
     &       * dsqrt(dfloat( (lmm-1)*lmm*lpmp1*(lpm+2) ))
            aux = aux + Qlm(ipm-2)
     &       * dsqrt(dfloat( lmmp1*(lmm+2)*(lpm-1)*lpm ))
            aux =  0.25d0 * aux

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

 60      continue
 70   continue


      end SUBROUTINE