LCOV - code coverage report
Current view: top level - vgen - psqpw.F90 (source / functions) Coverage Total Hit
Test: FLEUR test coverage Lines: 100.0 % 84 84
Test Date: 2025-11-24 04:36:21 Functions: 100.0 % 1 1

            Line data    Source code
       1              : module m_psqpw
       2              :   !     ***********************************************************
       3              :   !     generates the fourier coefficients of pseudo charge density
       4              :   !
       5              :   !     For yukawa_residual = .true. the subroutines calculate the
       6              :   !     pseudo charge density for the generation of the Yukawa
       7              :   !     potential instead of the Coulomb potential. This is used in
       8              :   !     the preconditioning of the SCF iteration for metallic systems.
       9              :   !
      10              :   !     references:
      11              :   !     for both the Coulomb and Yukawa cases:
      12              :   !     F. Tran, P. Blaha: Phys. Rev. B 83, 235118 (2011)
      13              :   !     or see the original paper for the normal Coulomb case only:
      14              :   !     M. Weinert: J. Math. Phys. 22(11) (1981) p.2434 eq. (10)-(15)
      15              :   !     ***********************************************************
      16              : 
      17              : contains
      18              : 
      19         1768 :   subroutine psqpw( fmpi, atoms, sphhar, stars, vacuum,  cell, input, sym, juphon,  &
      20         1768 :        &     den, ispin, l_xyav, potdenType, psq, sigma_disc, rhoimag, stars2, iDtype, iDir, rho0, iDir2 )
      21              : 
      22              : #ifdef CPP_MPI
      23              :     use mpi
      24              : #endif
      25              :     use m_constants
      26              :     use m_phasy1
      27              :     use m_mpmom
      28              :     use m_sphbes
      29              :     use m_qsf
      30              :     USE m_mpi_reduce_tool
      31              :      
      32              :      
      33              :     use m_types
      34              :     use m_DoubleFactorial
      35              :     use m_SphBessel
      36              :     implicit none
      37              : 
      38              :     type(t_mpi),        intent(in)  :: fmpi
      39              :     type(t_atoms),      intent(in)  :: atoms
      40              :     type(t_sphhar),     intent(in)  :: sphhar
      41              :     type(t_stars),      intent(in)  :: stars
      42              :     type(t_vacuum),     intent(in)  :: vacuum
      43              :     type(t_cell),       intent(in)  :: cell
      44              :     type(t_input),      intent(in)  :: input
      45              :     type(t_sym),        intent(in)  :: sym
      46              :     type(t_juphon),     intent(in)  :: juphon
      47              :     type(t_potden),     intent(in)  :: den
      48              :      
      49              :     logical,            intent(in)  :: l_xyav
      50              :     !complex,            intent(in)  :: qpw(stars%ng3)
      51              :     !real,               intent(in)  :: rho(atoms%jmtd,0:sphhar%nlhd,atoms%ntype)
      52              :     !real,               intent(in)  :: rht(vacuum%nmzd,2)
      53              :     integer,            intent(in)  :: potdenType, ispin
      54              :     complex,            intent(out) :: psq(stars%ng3)
      55              :     complex,            intent(out) :: sigma_disc(2)
      56              : 
      57              :     type(t_potden),optional,intent(in) :: rhoimag, rho0
      58              : 
      59              :     TYPE(t_stars), OPTIONAL, INTENT(IN) :: stars2
      60              : 
      61              :     INTEGER, OPTIONAL, INTENT(IN)   :: iDtype, iDir ! DFPT: Type and direction of displaced atom
      62              :     INTEGER, OPTIONAL, INTENT(IN)   :: iDir2
      63              : 
      64              :     complex                         :: psint, sa, sl, sm, qvac, fact, fc
      65              :     real                            :: f, fpo, gz, p, rmtl, s, fJ, gr, g
      66              :     integer                         :: ivac, k, l, n, n1, nc, ncvn, lm, ll1, nd, m, nz, kStart, kEnd
      67         1768 :     complex                         :: psq_local(stars%ng3)
      68         1768 :     complex                         :: pylm(( atoms%lmaxd + 1 ) ** 2, atoms%ntype)
      69         1768 :     complex                         :: qlm(-atoms%lmaxd:atoms%lmaxd,0:atoms%lmaxd,atoms%ntype)
      70         1768 :     complex                         :: q2(vacuum%nmzd)
      71         1768 :     real                            :: q2r(vacuum%nmzd),q2i(vacuum%nmzd)
      72         1768 :     real                            :: pn(0:atoms%lmaxd,atoms%ntype)
      73         4618 :     real                            :: aj(0:atoms%lmaxd+maxval(atoms%ncv)+1)
      74         1768 :     real, allocatable, dimension(:) :: il, kl
      75         1768 :     real                            :: g0(atoms%ntype)
      76         1768 :     complex                         :: qpw(stars%ng3)
      77         1768 :     real                            :: rho(atoms%jmtd,0:sphhar%nlhd,atoms%ntype)
      78         1768 :     complex                         :: rht(vacuum%nmzd,2)
      79              :     LOGICAL :: l_dfptvgen ! If this is true, we handle things differently!
      80              : 
      81              : #ifdef CPP_MPI
      82              :     integer                         :: ierr
      83              : #endif
      84              : 
      85         1768 :     l_dfptvgen = PRESENT(stars2)
      86      4329175 :     qpw = den%pw(:,ispin)
      87    100062550 :     rho = den%mt(:,:,:,ispin)
      88       260298 :     IF (input%film) rht = den%vac(:,1,:,ispin)
      89         1768 :     sigma_disc = cmplx(0.0,0.0)
      90              : 
      91              :     ! Calculate multipole moments
      92         1768 :     call timestart("mpmom")
      93              :     ! DFPT case:
      94              :     ! Additional contributions to qlm due to surface corrections.
      95              :     call mpmom( input, fmpi, atoms, sphhar, stars, sym, juphon, cell,   qpw, rho, potdenType, qlm, ispin, &
      96         1768 :               & rhoimag=rhoimag, stars2=stars2, iDtype=iDtype, iDir=iDir, rho0=rho0, iDir2=iDir2 )
      97         1768 :     call timestop("mpmom")
      98              : 
      99      4329175 :     psq(:) = cmplx( 0.0, 0.0 )
     100      4329175 :     psq_local(:) = cmplx( 0.0, 0.0 )
     101              : #ifdef CPP_MPI
     102         1768 :     call MPI_BCAST( qpw, size(qpw), MPI_DOUBLE_COMPLEX, 0, fmpi%mpi_comm, ierr )
     103         1768 :     nd = ( 2 * atoms%lmaxd + 1 ) * ( atoms%lmaxd + 1 ) * atoms%ntype
     104         1768 :     call MPI_BCAST( qlm, nd, MPI_DOUBLE_COMPLEX, 0, fmpi%MPI_COMM, ierr )
     105              : #endif
     106              : 
     107              :     ! prefactor in (A10) (Coulomb case) or (A11) (Yukawa case)
     108              :     ! nc(n) is the integer p in the paper; ncv(n) is l + p
     109              :     ! Coulomb case: pn(l,n) = (2 * l + 2 * p + 3)!! / ( (2 * l + 1)!! * R ** (ncv(n) + 1) ),
     110              :     ! Yukawa case: pn(l,n) = lambda ** (l + p + 1) / ( i_{l+p+1}(lambda * R) * (2 * l + 1)!! )
     111              :     ! g0 is the prefactor for the q=0 component in (A13)
     112        28320 :     pn = 0.
     113         4618 :     do n = 1, atoms%ntype
     114         4618 :       if ( potdenType /= POTDEN_TYPE_POTYUK ) then
     115        23924 :         do l = 0, min( atoms%ncv(n) - 1, atoms%lmax(n) )
     116        23924 :           pn(l, n) = DoubleFactorial( atoms%ncv(n) + 1, l ) / ( atoms%rmt(n) ** ( atoms%ncv(n) + 1 ) )
     117              :         end do
     118              :       else
     119           40 :         allocate( il(0:atoms%ncv(n)+1), kl(0:atoms%ncv(n)+1) )
     120           40 :         call ModSphBessel( il(0:), kl(0:), input%preconditioning_param * atoms%rmt(n), atoms%ncv(n) + 1 )
     121           40 :         g0(n) = ( input%preconditioning_param * atoms%rmt(n) ) ** ( atoms%ncv(n) + 1 ) / DoubleFactorial( atoms%ncv(n) + 1 ) / il( atoms%ncv(n) + 1 ) !p=ncv(n)
     122          360 :         do l = 0, min( atoms%ncv(n) - 1, atoms%lmax(n) )
     123          360 :           pn(l, n) = input%preconditioning_param ** ( atoms%ncv(n) + 1 ) / il( atoms%ncv(n) + 1 ) / DoubleFactorial( l )
     124              :         end do
     125           40 :         deallocate( il, kl )
     126              :       end if
     127              :     end do
     128              : 
     129              :     ! q=0 term: see (A12) (Coulomb case) or (A13) (Yukawa case)
     130         7072 :     if( fmpi%irank == 0 .AND. norm2(stars%center)<=1e-8) then
     131              :        s = 0.
     132         2282 :        do n = 1, atoms%ntype
     133         2282 :          if ( potdenType /= POTDEN_TYPE_POTYUK ) then
     134         1385 :            s = s + atoms%neq(n) * real( qlm(0,0,n) )
     135              :          else
     136           25 :            s = s + atoms%neq(n) * real( qlm(0,0,n) ) * g0(n)
     137              :          end if
     138              :        end do
     139              :     !if( fmpi%irank == 0 ) then
     140          872 :        psq_local(1) = qpw(1) + ( sfp_const / cell%omtil ) * s
     141              :     end if
     142              : 
     143              :     ! q/=0 term: see (A10) (Coulomb case) or (A11) (Yukawa case)
     144         1768 :     fpo = 1. / cell%omtil
     145              : 
     146         1768 :     call timestart("loop in psqpw")
     147              : 
     148         7482 :     CALL calcIndexBounds(fmpi, MERGE(2,1,norm2(stars%center)<=1e-8), stars%ng3, kStart, kEnd)
     149              :     !$OMP parallel do default( NONE ) &
     150              :     !$OMP SHARED(atoms,stars,sym,cell,kStart,kEnd,psq_local,qpw,qlm,pn,fpo,iDir,iDir2,iDtype) &
     151         1768 :     !$OMP private( pylm, sa, n, ncvn, aj, sl, l, n1, ll1, sm, m, lm )
     152              :     do k = kStart, kEnd
     153              :       call phasy1( atoms, stars, sym, cell, k, pylm )
     154              :       sa = 0.0
     155              :       do n = 1, atoms%ntype
     156              :         ncvn = atoms%ncv(n)
     157              :         call sphbes( ncvn + 1 , stars%sk3(k) * atoms%rmt(n), aj )
     158              :         sl = 0.
     159              :         do l = 0, atoms%lmax(n)
     160              :           IF(l.LT.ncvn) THEN
     161              :              n1 = ncvn - l + 1
     162              :              ll1 = l * ( l + 1 ) + 1
     163              :              sm = 0.
     164              :              do m = -l, l
     165              :                lm = ll1 + m
     166              :                sm = sm + qlm(m,l,n) * conjg( pylm(lm,n) )
     167              :              end do
     168              :           END IF
     169              :         sl = sl + pn(l,n) / ( stars%sk3(k) ** n1 ) * aj( ncvn + 1 ) * sm
     170              :         end do
     171              :         sa = sa + atoms%neq(n) * sl
     172              :         IF (PRESENT(iDir2)) THEN
     173              :           IF (iDir2==iDir) THEN
     174              :             IF (n==iDtype.OR.0==iDtype) THEN 
     175              :               sa = sa + atoms%zatom(n) * 5 * pn(2,n) * conjg(pylm(1,n)) * aj( ncvn + 1 ) / sfp_const / ( stars%sk3(k) ** (ncvn-1) )
     176              :             END IF
     177              :           END IF
     178              :         END IF
     179              :       end do
     180              :       psq_local(k) = qpw(k) + fpo * sa
     181              :     end do
     182              :     !$omp end parallel do
     183              : 
     184         1768 :     CALL mpi_sum_reduce(psq_local,psq,fmpi%MPI_COMM)
     185              : 
     186         1768 :     call timestop("loop in psqpw")
     187              : 
     188         7072 :     IF (.NOT.norm2(stars%center)<1e-8) RETURN ! TODO: Change this!
     189              :     !IF (l_dfptvgen) RETURN
     190              :     ! TODO: As of yet unclear if we need to do somecorrection here for
     191              :     !       DFPT, to make up for possible charge shifts from/to the vacuum.
     192              : 
     193         1358 :     if ( fmpi%irank == 0 ) then
     194          872 :       if ( potdenType == POTDEN_TYPE_POTYUK ) return
     195              :       ! Check: integral of the pseudo charge density within the slab
     196          864 :       if ( input%film ) then
     197          259 :         psint = psq(1) * stars%nstr(1) * vacuum%dvac
     198      1325603 :         do k = 2, stars%ng3
     199      1325603 :           if ( stars%ig2(k) == 1 ) then
     200        10644 :             gz = stars%kv3(3,k) * cell%bmat(3,3)
     201        10644 :             f = 2. * sin( gz * cell%z1 ) / gz
     202        10644 :             psint = psint + stars%nstr(k) * psq(k) * f
     203              :           end if
     204              :         end do
     205          259 :         psint = cell%area * psint
     206              :       else if ( .not. input%film ) then
     207          605 :         psint = psq(1) * stars%nstr(1) * cell%omtil
     208              :       end if
     209          864 :       write(oUnit, fmt=8000 ) psint
     210              : 8000  format (/,10x,'integral of pseudo charge density inside the slab='&
     211              :             &       ,5x,2f11.6)
     212          864 :       if ( .not. input%film .or. potdenType == POTDEN_TYPE_POTYUK ) return
     213              : 
     214              :       ! Normalized pseudo density
     215          259 :         qvac = cmplx(0.0,0.0)
     216          752 :         do ivac = 1, vacuum%nvac
     217          493 :           if (.not.l_dfptvgen) then
     218        18396 :             call qsf( vacuum%delz, real(rht(:,ivac)), q2r, vacuum%nmz, 0 )
     219        18323 :             q2 = q2r
     220              :           else
     221       105840 :             call qsf( vacuum%delz, real(rht(:,ivac)), q2r, vacuum%nmz, 0 )
     222       105420 :             call qsf( vacuum%delz,aimag(rht(:,ivac)), q2i, vacuum%nmz, 0 )
     223       105420 :             q2 = q2r + ImagUnit*q2i
     224              :           end if
     225          493 :           q2(1) = q2(1) * cell%area
     226          752 :           qvac = qvac + q2(1) * 2. / real( vacuum%nvac )
     227              :         end do
     228              :         !TODO: reactivate electric fields
     229              :         !qvac = qvac - 2 * input%sigma
     230          259 :       if ( l_xyav ) return
     231          259 :       fact = ( qvac + psint ) / ( stars%nstr(1) * cell%vol )
     232          259 :       psq(1) = psq(1) - fact
     233              :       ! Find discontinuity at the boundaries
     234      1325862 :       do k = 1, stars%ng3
     235      1325862 :          if ( stars%ig2(k) == 1 ) then
     236        10903 :             gz = stars%kv3(3,k) * cell%bmat(3,3)
     237        10903 :             fc = cmplx(cos(gz * cell%z1),sin(gz * cell%z1))
     238        10903 :             sigma_disc(1) = sigma_disc(1) - stars%nstr(k) * psq(k) * fc
     239        10903 :             sigma_disc(2) = sigma_disc(2) + stars%nstr(k) * psq(k) * conjg(fc)
     240              :          end if
     241              :       end do
     242              :       sigma_disc(1) = sigma_disc(1) + rht(1,1)
     243              :       sigma_disc(2) = sigma_disc(2) - rht(1,2)
     244          259 :       sigma_disc = 0.0 
     245              : 8010  format (/,10x,'                     1000 * normalization const. ='&
     246              :             &       ,5x,2f11.6)
     247              :     end if ! fmpi%irank == 0
     248              : 
     249              :   end subroutine psqpw
     250              : 
     251              : end module m_psqpw
        

Generated by: LCOV version 2.0-1