strmat.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: Calculation of lattice sums for \(l \leq 2l_{pot}\)
!> Author: B. Drittler
!> Calculation of lattice sums for \(l \leq 2l_{pot}\)
!> \begin{equation}
!> \sum_{rm} \frac{Y_{lm}\left(q(i)-q(j)-rm\right)}{\left| q(i)-q(j)-rm\right|^{l+1}}
!> \end{equation}
!> in the case of \(i = j\), \(rm = 0\) is omitted. Rhe ewald method is used to 
!> perform the lattice summations the splitting parameter \(\lambda\) is set equal 
!> \(\frac{\sqrt(\pi)}{a_{lat}}\) (\(a_{lat}\) is the lattice constant).
!> If the contribution of the last shell of the direct and the reciprocal lattice 
!> is greater than `1.0e-8` a message is written 
!------------------------------------------------------------------------------------
!> @note V. Popescu May 2004: Dimension of arrays GN,RM changed from `(4,*)` to 
!> `(3,*)`, the 4th one not being used (see also `lattice3d`).
!> @endnote
!------------------------------------------------------------------------------------
module mod_strmat

contains

  !-------------------------------------------------------------------------------
  !> Summary: Calculation of lattice sums for \(l \leq 2l_{pot}\)
  !> Author: B. Drittler
  !> Category: electrostatics, geometry, k-points, KKRhost
  !> Deprecated: False 
  !> Calculation of lattice sums for \(l \leq 2l_{pot}\)
  !> \begin{equation}
  !> \sum_{rm} \frac{Y_{lm}\left(q(i)-q(j)-rm\right)}{\left| q(i)-q(j)-rm\right|^{l+1}}
  !> \end{equation}
  !> in the case of \(i = j\), \(rm = 0\) is omitted. Rhe ewald method is used to 
  !> perform the lattice summations the splitting parameter \(\lambda\) is set equal 
  !> \(\frac{\sqrt(\pi)}{a_{lat}}\) (\(a_{lat}\) is the lattice constant).
  !> If the contribution of the last shell of the direct and the reciprocal lattice 
  !> is greater than `1.0e-8` a message is written 
  !-------------------------------------------------------------------------------
  !> @note V. Popescu May 2004: Dimension of arrays GN,RM changed from `(4,*)` to 
  !> `(3,*)`, the 4th one not being used (see also `lattice3d`).
  !> @endnote
  !-------------------------------------------------------------------------------
  subroutine strmat(alat,lpot,naez,ngmax,nrmax,nsg,nsr,nshlg,nshlr,gn,rm,qi0,smat,  &
    vol,iprint,lassld,lmxspd,naezd)

#ifdef CPP_HYBRID
#define CPP_OMPSTUFF
#endif
#ifdef CPP_OMP
#define CPP_OMPSTUFF
#endif
#ifdef CPP_OMPSTUFF
    use :: omp_lib
#endif

    use :: mod_constants
    use :: mod_datatypes, only: dp
    use :: mod_ymy, only: ymy
    use :: mod_gamfc, only: gamfc

    implicit none
    ! ..
    ! .. Parameters ..
    real (kind=dp) :: bound
    parameter (bound=1.0e-8_dp)
    ! ..
    ! .. Scalar arguments ..
    real (kind=dp) :: alat, vol
    integer :: iprint, lpot, naez, ngmax, nrmax, nshlg, nshlr
    integer :: lassld, lmxspd, naezd
    ! ..
    ! .. Array arguments ..
    real (kind=dp) :: gn(3, *), qi0(3, *), rm(3, *), smat(lmxspd, naezd, *)
    integer :: nsg(*), nsr(*)
    ! ..
    ! .. Local scalars ..
    complex (kind=dp) :: bfac
    real (kind=dp) :: alpha, beta, dq1, dq2, dq3, dqdotg, expbsq, fpi, g1, g2, g3, ga
    real (kind=dp) :: lamda, r, r1, r2, r3, rfac, s
    integer :: i, i1, i2, it, l, lm, lmx, lmxsp, lfmt, m, nge, ngs, nre, nrs, nstart
    character (len=80) :: fmt
    ! ..
    ! .. Local arrays ..
    complex (kind=dp) :: stest(lmxspd)
    real (kind=dp) :: g(0:lassld), ylm(lmxspd), qi(3, naezd)
    ! ..................................................................

    lmx = 2*lpot
    lmxsp = (lmx+1)*(lmx+1)
    fpi = 4.0_dp*pi

    ! OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OUTPUT
    write (1337, '(5X,2A,/)') '< STRMAT > : ', 'calculating lattice sums'
    ! OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OUTPUT


    ! --> choose proper splitting parameter

    lamda = sqrt(pi)/alat

    ! --> loop over atoms per unit cell -- scale basis atoms with alat

    do i2 = 1, naez
      do i1 = 1, 3
        qi(i1, i2) = qi0(i1, i2)*alat
      end do
    end do

    ! OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OUTPUT
    if (iprint>2) then
      write (1337, 110)
      do i2 = 1, naez
        write (1337, 120) i2, (qi0(i,i2), i=1, 3)
      end do
      write (1337, 130)
    end if
    ! OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OUTPUT

    ! **********************************************************************
#ifdef CPP_OMPSTUFF
    ! $omp parallel do default(shared) private(DQ1, DQ2, DQ3, STEST) &
    ! $omp& private(LM, NSTART, IT, NRS, NGS, NRE, NGE, I, R1, R2) &
    ! $omp& private(R3 , R, YLM, ALPHA, G, L, RFAC, M, G1, G2) &
    ! $omp& private(G3, GA, BETA, EXPBSQ, DQDOTG, BFAC, S, I1, I2)
#endif
    do i1 = 1, naez
      do i2 = 1, naez
        ! ======================================================================
        dq1 = qi(1, i1) - qi(1, i2)
        dq2 = qi(2, i1) - qi(2, i2)
        dq3 = qi(3, i1) - qi(3, i2)

        stest(1) = -sqrt(fpi)/vol/(4.0_dp*lamda*lamda)
        do lm = 2, lmxsp
          stest(lm) = 0.0_dp
        end do

        ! --> exclude the origine and add correction if i1.eq.i2

        if (i1==i2) then
          stest(1) = stest(1) - lamda/pi
          nstart = 2
        else
          nstart = 1
        end if
        ! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        ! --> loop first over n-1 shells of real and reciprocal lattice - then
        ! add the contribution of the last shells to see convergence

        ! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        do it = 1, 2
          if (it==1) then
            nrs = nstart
            ngs = 2
            nre = nrmax - nsr(nshlr)
            nge = ngmax - nsg(nshlg)
          else
            nrs = nre + 1
            ngs = nge + 1
            nre = nrmax
            nge = ngmax
          end if

          ! --> sum over real lattice

          ! ---------------------------------------------------------------------
          do i = nrs, nre
            r1 = dq1 - rm(1, i)
            r2 = dq2 - rm(2, i)
            r3 = dq3 - rm(3, i)

            call ymy(r1, r2, r3, r, ylm, lmx)
            alpha = lamda*r
            call gamfc(alpha, g, lmx, r)

            ! IF (R>0.3D0 .or. .not. use_virtual_atoms ) THEN         ! added by bauer VIRTAOM
            do l = 0, lmx
              rfac = g(l)/sqrt(pi)
              do m = -l, l
                lm = l*(l+1) + m + 1
                stest(lm) = stest(lm) + ylm(lm)*rfac
              end do
            end do
            ! ELSE
            ! write(*,*) 'omitting ',R
            ! endif !(R>0.3) THEN         ! added by bauer VIRTAOM

          end do
          ! ---------------------------------------------------------------------

          ! --> sum over reciprocal lattice

          ! ---------------------------------------------------------------------
          do i = ngs, nge
            g1 = gn(1, i)
            g2 = gn(2, i)
            g3 = gn(3, i)

            call ymy(g1, g2, g3, ga, ylm, lmx)
            beta = ga/lamda
            dqdotg = dq1*g1 + dq2*g2 + dq3*g3

            if (beta>50.0_dp) then
              bfac = 0.0_dp
            else
              expbsq = exp(beta*beta/4.0_dp)
              bfac = fpi*exp(ci*dqdotg)/(ga*ga*expbsq*vol)
            end if

            do l = 0, lmx
              do m = -l, l
                lm = l*(l+1) + m + 1
                stest(lm) = stest(lm) + ylm(lm)*bfac
              end do
              bfac = bfac*ga/ci/real(2*l+1, kind=dp)
            end do
          end do
          ! ---------------------------------------------------------------------
          if (it==1) then
            do lm = 1, lmxsp
              if (abs(aimag(stest(lm)))>bound) then
                write (6, *) ' ERROR: Imaginary contribution', ' to REAL lattice sum'
                write(6, *) abs(aimag(stest(lm))), bound
                stop 
              end if
              smat(lm, i1, i2) = real(stest(lm), kind=dp)
              stest(lm) = 0.0_dp
            end do
          else

            ! --> test convergence

#ifdef CPP_OMPSTUFF
            ! $omp critical
#endif
            do lm = 1, lmxsp
              s = real(stest(lm), kind=dp)
              smat(lm, i1, i2) = smat(lm, i1, i2) + s
              if (abs(s)>bound) write (6, fmt=100) i1, i2, lm, abs(s)
            end do
#ifdef CPP_OMPSTUFF
            ! $omp end critical
#endif
          end if
          ! ---------------------------------------------------------------------
        end do
        ! +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      end do
    end do
#ifdef CPP_OMPSTUFF
    ! $omp end parallel do
#endif
    ! **********************************************************************

    if (iprint<2) return

    ! OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OUTPUT
    write (1337, 140) min(6, naez)
    fmt = ' '
    lfmt = 0
    do i = 1, min(6, naez)
      fmt = fmt(1:lfmt) // '------------'
      lfmt = lfmt + 12
    end do
    write (1337, '(7X,A)') fmt(1:lfmt)
    do i1 = 1, min(6, naez)
      write (1337, 150)(smat(1,i1,i2), i2=1, min(6,naez))
    end do
    write (1337, '(7X,A,/)') fmt
    ! OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO OUTPUT

100 format (5x, 'WARNING : Convergence of SMAT(', i2, ',', i2, ') ', ' for LMXSP =', i3, ' is ', 1p, d9.2, ' > 1D-8', /, 15x, 'You should use more lattice vectors (RMAX/GMAX)')
110 format (12x, 47('-'), /, 16x, '      Positions of atomic sites', /, 16x, '    in CARTESIAN coordinates (a.u.)', /, 12x, 47('-'), /, 15x, &
      'IQ       x           y           z     ', /, 12x, 47('-'))
120 format (13x, i5, 3f12.6)
130 format (12x, 47('-'), /)
140 format (8x, 'Lattice sum (LMXSP = 1) up to NAEZ =', i2)
150 format (7x, 6(d12.4))
  end subroutine strmat

end module mod_strmat