LCOV - code coverage report
Current view: top level - math - gradYlm.f90 (source / functions) Hit Total Coverage
Test: FLEUR test coverage Lines: 102 107 95.3 %
Date: 2024-04-28 04:28:00 Functions: 3 4 75.0 %

          Line data    Source code
       1             : MODULE m_gradYlm
       2             :    IMPLICIT NONE
       3             : 
       4             : CONTAINS
       5             : 
       6             :   ! Derivative routine from Spex.
       7             :   ! Calculates derivative of a function with scalar argument lying on a muffin-tin mesh
       8      196620 :   subroutine Derivative(f, itype, atoms, df)
       9             : 
      10             :     use m_types
      11             : 
      12             :      type(t_atoms), intent(in)  :: atoms
      13             : 
      14             :      integer,       intent(in)  :: itype
      15             :      real,          intent(in)  :: f(atoms%jri(itype))
      16             :      real,          intent(out) :: df(atoms%jri(itype))
      17             :      real                       :: h, r, d21, d32, d43, d31, d42, d41, df1, df2, s
      18             :      real                       :: y0, y1, y2
      19             :      integer                    :: i, n
      20             : 
      21      196620 :      n = atoms%jri(itype)
      22      196620 :      h = atoms%dx(itype)
      23      196620 :      r = atoms%rmsh(1, itype)
      24             : 
      25             :      ! use Lagrange interpolation of 3rd order (and averaging) for points 3 to n
      26      196620 :      d21 = r * (exp(h)-1) ; d32 = d21 * exp(h) ; d43 = d32 * exp(h)
      27      196620 :      d31 = d21 + d32      ; d42 = d32 + d43
      28      196620 :      d41 = d31 + d43
      29             :      df(1) =   d31*d41 / (d21*d32*d42) * f(2) + ( -1.0/d21 - 1.0/d31 - 1.0/d41) * f(1)&
      30      196620 :     &        - d21*d41 / (d31*d32*d43) * f(3) + d21*d31 / (d41*d42*d43) * f(4)
      31             :      df(2) = - d32*d42 / (d21*d31*d41) * f(1) + (  1.0/d21 - 1.0/d32 - 1.0/d42) * f(2)&
      32      196620 :     &        + d21*d42 / (d31*d32*d43) * f(3) - d21*d32 / (d41*d42*d43) * f(4)
      33             :      df1   =   d32*d43 / (d21*d31*d41) * f(1) - d31*d43 / (d21*d32*d42) * f(2) +&
      34      196620 :     &  ( 1.0/d31 + 1.0/d32 - 1.0/d43 ) * f(3) + d31*d32 / (d41*d42*d43) * f(4)
      35   138338700 :      do i = 3, n - 2
      36   138142080 :         d21 = d32 ; d32 = d43 ; d43 = d43 * exp(h)
      37   138142080 :         d31 = d42 ; d42 = d42 * exp(h)
      38   138142080 :         d41 = d41 * exp(h)
      39             :         df2   = - d32*d42 / (d21*d31*d41) * f(i-1) + ( 1.0/d21 - 1.0/d32 - 1.0/d42) * f(i) + &
      40   138142080 :     &             d21*d42 / (d31*d32*d43) * f(i+1) - d21*d32 / (d41*d42*d43) * f(i+2)
      41   138142080 :         df(i) = ( df1 + df2 ) / 2
      42             :         df1   = d32*d43 / (d21*d31*d41) * f(i-1) - d31*d43 / (d21*d32*d42) * f(i) +&
      43   138338700 :     &    ( 1.0/d31 + 1.0/d32 - 1.0/d43 ) * f(i+1) + d31*d32 / (d41*d42*d43) * f(i+2)
      44             :      enddo
      45      196620 :      df(n-1) = df1
      46             :      df(n)   = - d42*d43 / (d21*d31*d41) * f(n-3) + d41*d43 / (d21*d32*d42) * f(n-2) -&
      47      196620 :     &            d41*d42 / (d31*d32*d43) * f(n-1) + ( 1.0/d41 + 1.0/d42 + 1.0/d43 ) * f(n)
      48             :      ! for first two points use Lagrange interpolation of second order for log(f(i))
      49             :      ! or, as a fall-back, Lagrange interpolation with the conditions f(1), f(2), f(3), f'(3).
      50      196620 :      s = sign(1.0,f(1))
      51      578913 :      if(sign(1.0,f(2)) /= s .or. sign(1.0,f(3))  /= s .or. any(f(:3) == 0)) then
      52       70897 :         d21   = r * (exp(h)-1)
      53       70897 :         d32   = d21 * exp(h)
      54       70897 :         d31   = d21 + d32
      55       70897 :         s     = df(3) / (d31*d32) - f(1) / (d21*d31**2) + f(2) / (d21*d32**2) - f(3) / (d31**2*d32) - f(3) / (d31*d32**2)
      56       70897 :         df(1) = - (d21+d31) / (d21*d31) * f(1) + d31 / (d21*d32) * f(2) - d21 / (d31*d32) * f(3) + d21*d31 * s
      57             : 
      58       70897 :         df(2) = - (d21-d32) / (d21*d32) * f(2) - d32 / (d21*d31) * f(1) + d21 / (d31*d32) * f(3) - d21*d32 * s
      59             :      else
      60      125723 :         y0    = log(abs(f(1)))
      61      125723 :         y1    = log(abs(f(2)))
      62      125723 :         y2    = log(abs(f(3)))
      63      125723 :         df(1) = ( - 3*y0/2 + 2*y1 - y2/2 ) * f(1) / (h*r)
      64      125723 :         df(2) = (y2-y0)/2                  * f(2) / (h*r*exp(h))
      65             :      endif
      66      196620 :   end subroutine Derivative
      67             : 
      68         194 :    SUBROUTINE gradYlm(atoms, r2FshMt, r2GrFshMt)
      69             :    ! Based on work for juphon by C. Gerhorst.
      70             :   !---------------------------------------------------------------------------------------------------------------------------------
      71             :   !> @author
      72             :   !> Christian-Roman Gerhorst, Forschungszentrum Jülich: IAS1 / PGI1
      73             :   !>
      74             :   !> @brief
      75             :   !> Calculates the spherical harmonic expansion coefficients of the muffin-tin gradient applied to an arbitrary function multiplied
      76             :   !> by $r^2$. The resulting gradient expansion coefficients are multiplied by a factor $r^2$.
      77             :   !>
      78             :   !> @note
      79             :   !> The ingoing function is assumed to be multiplied with $r^2$. The outgoing resulting function is also multiplied by $r^2$.
      80             :   !>
      81             :   !> @param[in]  atoms     : Contains atoms-related quantities; definition of its members in types.F90 file.
      82             :   !> @param[in]  r2FshMt   : Lattice harmonic coefficients of muffin-tin quantity multiplied by a factor of r**2.
      83             :   !> @param[out] r2GrFshMt : Spherical harmonic coefficients of muffin-tin quantity's gradient multiplied by a factor of r**2
      84             :   !---------------------------------------------------------------------------------------------------------------------------------
      85             : 
      86             :     use m_constants, only : fpi_const, ImagUnit
      87             :     use m_gaunt, only : gaunt1
      88             :     use m_types
      89             : 
      90             : 
      91             :     ! Type parameter
      92             :     ! ***************
      93             :     type(t_atoms),                     intent(in)  :: atoms
      94             : 
      95             :     ! Array parameters
      96             :     ! ****************
      97             :     complex,       allocatable,        intent(in)  :: r2FshMt(:, :, :)
      98             :     complex,       allocatable,        intent(out) :: r2GrFshMt(:, :, :, :)
      99             : 
     100             : 
     101             :     ! Local Scalar Variables
     102             :     ! **********************
     103             :     ! pfac     : Prefactor
     104             :     ! tGaunt   : Gaunt coefficient
     105             :     ! itype    : Loop index for atom types
     106             :     ! ieqat    : Loop index for equivalent atoms
     107             :     ! iatom    : Loop index for all atoms
     108             :     ! imesh    : Loop index for radial mesh point
     109             :     ! mqn_m    : Magnetic quantum number m
     110             :     ! oqn_l    : Orbital quantum number l
     111             :     ! mqn_mpp  : Magnetic quantum number double primed to index the natural coordinates
     112             :     ! lmInput  : Collective index for orbital and magnetic quantum number used for input function
     113             :     ! lmOutput : Collective index for orbital and magnetic quantum number used for output function
     114             :     real                                           :: pfac
     115             :     real                                           :: tGaunt
     116             :     integer                                        :: itype
     117             :     integer                                        :: ieqat
     118             :     integer                                        :: iatom
     119             :     integer                                        :: imesh
     120             :     integer                                        :: mqn_m
     121             :     integer                                        :: oqn_l
     122             :     integer                                        :: mqn_mpp
     123             :     integer                                        :: lmOutput
     124             :     integer                                        :: lmInput
     125             : 
     126             :     ! Local Array Variables
     127             :     ! *********************
     128             :     ! rDerFlhMtre  : Real part of the radial derrivative applied to the incoming fuction coefficients
     129             :     ! rDerFlhMtim  : Imaginary part of the radial derrivative applied to the incoming fuction coefficients
     130             :     ! rDerFlhMt    : Radial derrivative of the incoming fuction
     131             :     ! r2GrFshMtNat : Expansion coefficients of the muffin-tin gradient applied to the incoming function. The coefficients are given
     132             :     !                in natural coordinates and multiplied by $r^2$
     133         194 :     real,          allocatable                     :: r2FshMtre(:)
     134         194 :     real,          allocatable                     :: r2FshMtim(:)
     135         194 :     real,          allocatable                     :: rDerFshMtre(:)
     136         194 :     real,          allocatable                     :: rDerFshMtim(:)
     137         194 :     real,          allocatable                     :: rDerJunk(:)
     138         194 :     complex,       allocatable                     :: rDerFshMt(:)
     139         194 :     complex,       allocatable                     :: r2GrFshMtNat(:, :, :, :)
     140             :     !Matrix syntax idea from http://stackoverflow.com/questions/3708307/how-to-initialize-two-dimensional-arrays-in-fortran
     141             :     complex, dimension(3, 3)  :: Tmatrix !no parameter anymore since the init below is not OK for this
     142             :     Tmatrix = transpose(reshape([                                                          &
     143             :                                                                    & cmplx(1 / sqrt(2.), 0), cmplx(0, 0), cmplx(-1 / sqrt(2.), 0), &
     144             :                                                                    & -ImagUnit / sqrt(2.), cmplx(0, 0), -ImagUnit / sqrt(2.), &
     145             :                                                                    & cmplx(0, 0), cmplx(1, 0), cmplx(0, 0) &
     146         194 :                                                                    & ], [3, 3] )) ! see my notes
     147             : 
     148             : 
     149             :     ! Initialization of additionaly required arrays.
     150        1164 :     allocate( r2GrFshMt(atoms%jmtd, ( atoms%lmaxd + 2 )**2, atoms%nat, 3) )
     151         776 :     allocate( r2GrFshMtNat(atoms%jmtd, ( atoms%lmaxd + 2 )**2, atoms%nat, 3) )
     152        1746 :     allocate( r2FshMtre(atoms%jmtd), r2FshMtim(atoms%jmtd), rDerFshMtre(atoms%jmtd), rDerFshMtim(atoms%jmtd), rDerJunk(atoms%jmtd), rDerFshMt(atoms%jmtd) )
     153             : 
     154      135658 :     r2FshMtre(:) = 0.
     155      135658 :     r2FshMtim(:) = 0.
     156      135658 :     rDerFshMtre(:) = 0.
     157      135658 :     rDerFshMtim(:) = 0.
     158      135658 :     rDerFshMt(:) = 0.
     159    47975654 :     r2GrFshMt = cmplx(0., 0.)
     160    47975654 :     r2GrFshMtNat = cmplx(0., 0.)
     161             : 
     162             :     pfac = sqrt( fpi_const / 3 )
     163         776 :     do mqn_mpp = -1, 1
     164         582 :       iatom = 0
     165        1454 :       do itype = 1, atoms%ntype
     166        1938 :         do ieqat = 1, atoms%neq(itype)
     167         678 :           iatom = iatom + 1
     168        7458 :           do oqn_l = 0, atoms%lmax(itype)
     169       61698 :             do mqn_m = -oqn_l, oqn_l
     170             : 
     171             :               ! l + 1 block
     172       54918 :               if ( abs(mqn_m - mqn_mpp) <= oqn_l + 1 ) then
     173       54918 :                 lmOutput = ( oqn_l + 1 ) * ( oqn_l + 2 ) + 1 + mqn_m - mqn_mpp
     174       54918 :                 lmInput = oqn_l * ( oqn_l + 1 ) + 1 + mqn_m
     175    38859102 :                 r2FshMtre(:) = 0.
     176    38859102 :                 r2FshMtim(:) = 0.
     177    38859102 :                 rDerFshMtre(:) = 0.
     178    38859102 :                 rDerFshMtim(:) = 0.
     179             :                 ! This is also a trade of between storage and performance, because derivative is called redundantly, maybe store it?
     180    38859102 :                 r2FshMtre(:)=real(r2FshMt(:, lmInput, itype))
     181    38859102 :                 r2FshMtim(:)=aimag(r2FshMt(:, lmInput, itype))
     182       54918 :                 call Derivative( r2FshMtre, itype, atoms, rDerFshMtre )
     183       54918 :                 call Derivative( r2FshMtim, itype, atoms, rDerFshMtim )
     184             : 
     185       54918 :                 tGaunt = Gaunt1( oqn_l + 1, oqn_l, 1, mqn_m - mqn_mpp, mqn_m, -mqn_mpp, atoms%lmaxd + 1 )
     186    38859102 :                 do imesh = 1, atoms%jri(itype)
     187    38804184 :                   rDerFshMt(imesh) = cmplx(rDerFshMtre(imesh), rDerFshMtim(imesh))
     188             :                   r2GrFshMtNat(imesh, lmOutput, iatom, mqn_mpp + 2) = r2GrFshMtNat(imesh, lmOutput, iatom, mqn_mpp + 2) + pfac *   &
     189             :                     & (-1)**mqn_mpp * tGaunt &
     190    38859102 :                     & * (rDerFshMt(imesh) - ((oqn_l + 2)* r2FshMt(imesh, lmInput, iatom) / atoms%rmsh(imesh, itype)))
     191             :                 end do ! imesh
     192             :               end if ! ( abs(mqn_m - mqn_mpp) <= oqn_l + 1 )
     193             : 
     194             :               ! l - 1 block
     195       61020 :               if ( abs(mqn_m - mqn_mpp) <= oqn_l - 1 ) then
     196       43392 :                 lmInput = oqn_l * ( oqn_l + 1 ) + 1 + mqn_m
     197       43392 :                 lmOutput = (oqn_l - 1) * oqn_l + 1 + mqn_m - mqn_mpp
     198    30703488 :                 r2FshMtre(:) = 0.
     199    30703488 :                 r2FshMtim(:) = 0.
     200    30703488 :                 rDerFshMtre(:) = 0.
     201    30703488 :                 rDerFshMtim(:) = 0.
     202             :                 ! This is also a trade of between storage and performance, because derivative is called redundantly, maybe store it?
     203    30703488 :                 r2FshMtre(:)=real(r2FshMt(:, lmInput, itype))
     204    30703488 :                 r2FshMtim(:)=aimag(r2FshMt(:, lmInput, itype))
     205       43392 :                 call Derivative( r2FshMtre, itype, atoms, rDerFshMtre )
     206       43392 :                 call Derivative( r2FshMtim, itype, atoms, rDerFshMtim )
     207             : 
     208       43392 :                 tGaunt = Gaunt1( oqn_l - 1, oqn_l, 1, mqn_m - mqn_mpp, mqn_m, -mqn_mpp, atoms%lmaxd + 1 )
     209    30703488 :                 do imesh = 1, atoms%jri(itype)
     210    30660096 :                   rDerFshMt(imesh) = cmplx(rDerFshMtre(imesh), rDerFshMtim(imesh))
     211             :                   r2GrFshMtNat(imesh, lmOutput, iatom, mqn_mpp + 2) = r2GrFshMtNat(imesh, lmOutput, iatom, mqn_mpp + 2) + pfac *   &
     212             :                     & (-1)**mqn_mpp * tGaunt * ( rDerFshMt(imesh) + ( (oqn_l - 1) * r2FshMt(imesh, lmInput, iatom)&
     213    30703488 :                     & / atoms%rmsh(imesh, itype) ) )
     214             :                 enddo ! imesh
     215             :               end if ! ( abs(mqn_m - mqn_mpp) <= oqn_l - 1 )
     216             :             end do ! mqn_m
     217             :           end do ! oqn_l
     218             :         end do ! ieqat
     219             :       end do ! itype
     220             :     end do ! mqn_mpp
     221             : 
     222             :     ! Conversion from natural to cartesian coordinates
     223         194 :     iatom = 0
     224         420 :     do itype = 1, atoms%ntype
     225         646 :       do ieqat = 1, atoms%neq(itype)
     226         226 :         iatom = iatom + 1
     227        2712 :         do oqn_l = 0, atoms%lmax(itype) + 1
     228       25086 :           do mqn_m = -oqn_l, oqn_l
     229       22600 :             lmOutput = oqn_l * (oqn_l + 1) + 1 + mqn_m
     230    15993660 :             do imesh = 1, atoms%jri(itype)
     231   271492200 :               r2GrFshMt(imesh, lmOutput, iatom, 1:3) = matmul( Tmatrix(1:3, 1:3), r2GrFshMtNat(imesh, lmOutput, iatom, 1:3) )
     232             :             end do ! imesh
     233             :           end do ! mqn_m
     234             :         end do ! oqn_l
     235             :       end do ! ieqat
     236             :     end do ! itype
     237             : 
     238         194 :    END SUBROUTINE gradYlm
     239             : 
     240          64 :    SUBROUTINE divYlm(gradMtx, gradMty, gradMtz, divMt)
     241             :       COMPLEX, INTENT(IN) :: gradMtx(:,:,:,:), gradMty(:,:,:,:), gradMtz(:,:,:,:) !r,lm,n,x
     242             :       COMPLEX, INTENT(OUT) :: divMt(:,:,:)
     243             : 
     244     4235952 :       divMt(:,:,:)=gradMtx(:,:,:,1)+gradMty(:,:,:,2)+gradMtz(:,:,:,3)
     245             : 
     246          64 :    END SUBROUTINE divYlm
     247             : 
     248           0 :    SUBROUTINE rotYlm(gradMtx, gradMty, gradMtz, rotMt)
     249             :       COMPLEX, INTENT(IN) :: gradMtx(:,:,:,:), gradMty(:,:,:,:), gradMtz(:,:,:,:) !r,lm,n,x
     250             :       COMPLEX, INTENT(OUT) :: rotMt(:,:,:,:)
     251             : 
     252           0 :       rotMt(:,:,:,1)=gradMtz(:,:,:,2)-gradMty(:,:,:,3)
     253           0 :       rotMt(:,:,:,2)=gradMtx(:,:,:,3)-gradMtz(:,:,:,1)
     254           0 :       rotMt(:,:,:,3)=gradMty(:,:,:,1)-gradMtx(:,:,:,2)
     255             : 
     256           0 :    END SUBROUTINE rotYlm
     257             : END MODULE m_gradYlm

Generated by: LCOV version 1.14