LCOV - code coverage report
Current view: top level - src/65_paw - m_paw_yukawa.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 107 0
Test Date: 2026-09-21 22:40:37 Functions: 0.0 % 4 0

            Line data    Source code
       1              : !!****m* m_paw_yukawa/m_paw_yukawa
       2              : !! NAME
       3              : !!  m_paw_yukawa
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module contains several routines related to the Yukawa parametrization
       7              : !!  of Coulomb interactions in the PAW approach.
       8              : !!
       9              : !! COPYRIGHT
      10              : !! Copyright (C) 2025-2026 ABINIT group
      11              : !! These routines are inspired by K. Haule routines in embedded DMFT.
      12              : !! This file is distributed under the terms of the
      13              : !! GNU General Public License, see ~abinit/COPYING
      14              : !! or http://www.gnu.org/copyleft/gpl.txt .
      15              : !!
      16              : !! SOURCE
      17              : 
      18              : #if defined HAVE_CONFIG_H
      19              : #include "config.h"
      20              : #endif
      21              : 
      22              : #include "abi_common.h"
      23              : 
      24              : MODULE m_paw_yukawa
      25              : 
      26              :  use defs_basis
      27              :  use m_abicore
      28              :  use m_errors
      29              :  use m_pawrad, only : pawrad_type
      30              : 
      31              :  implicit none
      32              : 
      33              :  private
      34              : 
      35              :  public :: compute_slater
      36              :  public :: get_lambda
      37              : 
      38              : CONTAINS  !========================================================================================
      39              : !!***
      40              : 
      41              : !!****f* m_paw_yukawa/compute_slater
      42              : !! NAME
      43              : !! compute_slater
      44              : !!
      45              : !! FUNCTION
      46              : !!
      47              : !! Compute Slater integrals for a screened Yukawa potential v(r,r') = exp(-lambda*(r-r'))/(epsilon*(r-r'))
      48              : !! This is eq. 36 in the supplementary of Physical review letters, Haule, K. (2015), 115(19), 196403
      49              : !!
      50              : !! INPUTS
      51              : !!  lpawu = angular momentum
      52              : !!  pawrad <type(pawrad_type)>=paw radial mesh and related data:
      53              : !!     %mesh_size=Dimension of radial mesh
      54              : !!     %rad(mesh_size)=The coordinates of all the points of the radial mesh
      55              : !!  proj2 = u(r)**2 where u(r) is the atomic orbital multiplied by r
      56              : !!  meshsz = size of the radial mesh
      57              : !!  lambda, eps = parameters of the Yukawa potential
      58              : !!
      59              : !! OUTPUT
      60              : !!  fk(lpawu+1)= Slater integrals
      61              : !!
      62              : !! SOURCE
      63              : 
      64            0 :  subroutine compute_slater(lpawu,pawrad,proj2,meshsz,lambda,eps,fk)
      65              : 
      66              :  use m_pawrad, only : pawrad_type,simp_gen
      67              :  use m_bessel2, only : bessel_iv,bessel_kv
      68              : 
      69              : !Arguments ------------------------------------
      70              :  integer, intent(in) :: lpawu,meshsz
      71              :  real(dp), intent(in) :: lambda,eps
      72              :  real(dp), intent(in) :: proj2(meshsz)
      73              :  real(dp), intent(inout) :: fk(lpawu+1)
      74              :  type(pawrad_type), intent(in) :: pawrad
      75              : !Local variables ------------------------------
      76              :  integer :: ir,k,mesh_type
      77              :  real(dp) :: dum,r_for_intg,y0
      78            0 :  real(dp), allocatable :: r_k(:),u_inside(:),u_outside(:),y1(:),y2(:)
      79              :  !************************************************************************
      80              : 
      81            0 :  mesh_type  = pawrad%mesh_type
      82            0 :  r_for_intg = pawrad%rad(meshsz)
      83            0 :  ABI_MALLOC(r_k,(meshsz))
      84            0 :  ABI_MALLOC(u_inside,(meshsz))
      85            0 :  ABI_MALLOC(u_outside,(meshsz))
      86              : 
      87            0 :  if (lambda == zero) then
      88              : 
      89            0 :    do k=0,2*lpawu+1,2
      90            0 :      u_inside(1) = zero
      91            0 :      r_k(:) = pawrad%rad(1:meshsz)**k
      92            0 :      do ir=2,meshsz
      93            0 :        if (ir == 2) then
      94              :          ! Use a trapezoidal rule
      95              :          u_inside(ir) = half * (proj2(1)*r_k(1)+proj2(2)*r_k(2)) * &
      96            0 :                  & (pawrad%rad(2)-pawrad%rad(1))
      97            0 :        else if (ir == 3 .and. mesh_type == 3) then
      98              :          ! simp_gen doesn't handle this case, so we use a trapezoidal rule instead
      99              :          u_inside(ir) = u_inside(2) + half*(proj2(2)*r_k(2)+proj2(3)*r_k(3))* &
     100            0 :                  & (pawrad%rad(3)-pawrad%rad(2))
     101              :        else
     102              :          ! Use Simpson rule when enough points are available
     103            0 :          call simp_gen(u_inside(ir),proj2(1:ir)*r_k(1:ir),pawrad,r_for_intg=pawrad%rad(ir))
     104              :        end if ! ir=2
     105              :      end do ! ir
     106            0 :      u_outside(1) = zero
     107            0 :      u_outside(2:meshsz) = two * u_inside(2:meshsz) * proj2(2:meshsz) / (pawrad%rad(2:meshsz)*r_k(2:meshsz))
     108            0 :      call simp_gen(fk(k/2+1),u_outside(:),pawrad,r_for_intg=r_for_intg)
     109              :    end do ! k
     110              : 
     111              :  else
     112              : 
     113            0 :    ABI_MALLOC(y1,(meshsz))
     114            0 :    ABI_MALLOC(y2,(meshsz))
     115              : 
     116            0 :    r_k(:) = sqrt(pawrad%rad(1:meshsz))
     117              : 
     118            0 :    do k=0,2*lpawu+1,2
     119              : 
     120            0 :      y0 = zero
     121            0 :      if (k == 0) y0 = lambda * sqrt(two/pi)
     122            0 :      y1(1) = y0
     123            0 :      u_inside(1) = zero
     124              : 
     125            0 :      do ir=2,meshsz
     126              : 
     127            0 :        call bessel_iv(half+dble(k),lambda*pawrad%rad(ir),zero,y1(ir),dum)
     128            0 :        y1(ir) = y1(ir) / r_k(ir)
     129              : 
     130            0 :        if (ir == 2) then
     131              :          ! Use a trapezoidal rule
     132              :          u_inside(ir) = half * (proj2(1)*y1(1)+proj2(2)*y1(2)) * &
     133            0 :                  & (pawrad%rad(2)-pawrad%rad(1))
     134            0 :        else if (ir == 3 .and. mesh_type == 3) then
     135              :          ! simp_gen doesn't handle this case, so we use a trapezoidal rule instead
     136              :          u_inside(ir) = u_inside(2) + half*(proj2(2)*y1(2)+proj2(3)*y1(3)) * &
     137            0 :                  & (pawrad%rad(3)-pawrad%rad(2))
     138              :        else
     139              :          ! Use Simpson rule when enough points are available
     140            0 :          call simp_gen(u_inside(ir),proj2(1:ir)*y1(1:ir),pawrad,r_for_intg=pawrad%rad(ir))
     141              :        end if ! ir
     142              : 
     143            0 :        call bessel_kv(half+dble(k),lambda*pawrad%rad(ir),zero,y2(ir),dum)
     144            0 :        y2(ir) = y2(ir) / r_k(ir)
     145              :      end do ! ir
     146              : 
     147            0 :      u_outside(1) = zero
     148            0 :      u_outside(2:meshsz) = two * (two*dble(k)+one)*u_inside(2:meshsz)*proj2(2:meshsz)*y2(2:meshsz)
     149            0 :      call simp_gen(fk(k/2+1),u_outside(:),pawrad,r_for_intg=r_for_intg)
     150              : 
     151              :    end do ! k
     152              : 
     153            0 :    ABI_FREE(y1)
     154            0 :    ABI_FREE(y2)
     155              : 
     156              :  end if ! lambda
     157              : 
     158            0 :  fk(1:lpawu+1) = fk(1:lpawu+1) / eps
     159              : 
     160            0 :  ABI_FREE(r_k)
     161            0 :  ABI_FREE(u_inside)
     162            0 :  ABI_FREE(u_outside)
     163              : 
     164            0 :  end subroutine compute_slater
     165              : !!***
     166              : 
     167              : !----------------------------------------------------------------------
     168              : 
     169              : !!****f* m_paw_yukawa/get_lambda
     170              : !! NAME
     171              : !! get_lambda
     172              : !!
     173              : !! FUNCTION
     174              : !!
     175              : !! Conversion from U,J,f4/f2,f6/f2 parametrization of Slater integrals
     176              : !! to lambda,epsilon parametrization, with lambda and epsilon the parameters
     177              : !! of the screened Yukawa potential v(r,r') = exp(-lambda*(r-r'))/(epsilon*(r-r')).
     178              : !!
     179              : !! CAREFUL: this routine does not handle custom f4/f2 and f6/f2 values, and set them
     180              : !!          to their default values f4/f2=0.625 for l=2 and f4/f2=0.6681, f6/f2=0.4943 for l=3.
     181              : !!
     182              : !! CAREFUL: For l>=2 we lose information since we have more input parameters than output
     183              : !!          parameters. In this case, a compromise has to be made, and you will no longer
     184              : !!          have the exact same Slater integrals as before.
     185              : !!
     186              : !! INPUTS
     187              : !!  lpawu = angular momentum
     188              : !!  pawrad <type(pawrad_type)>=paw radial mesh and related data:
     189              : !!     %mesh_size=Dimension of radial mesh
     190              : !!     %rad(mesh_size)=The coordinates of all the points of the radial mesh
     191              : !!  proj2 = u(r)**2 where u(r) is the atomic orbital multiplied by r
     192              : !!  meshsz = size of the radial mesh
     193              : !!  upawu,jpawu = parameters for Slater integrals
     194              : !!  yukawa_param = if set to 1, search for lambda and epsilon yielding the values closest to u and j
     195              : !!                 if set to 2, search for lambda yielding u, and set epsilon to 1
     196              : !!
     197              : !! OUTPUT
     198              : !!  lambda,epsilon = parameters of the corresponding Yukawa potential
     199              : !!
     200              : !! SOURCE
     201              : 
     202            0 :  subroutine get_lambda(lpawu,pawrad,proj2,meshsz,upawu,jpawu,lambda,eps,yukawa_param)
     203              : 
     204              :  use m_brentq, only : brentq
     205              :  use m_hybrd, only : hybrd
     206              : 
     207              : !Arguments ------------------------------------
     208              :  integer, intent(in) :: lpawu,meshsz,yukawa_param
     209              :  real(dp), intent(in) :: upawu,jpawu
     210              :  real(dp), intent(out) :: lambda,eps
     211              :  real(dp), intent(in) :: proj2(meshsz)
     212              :  type(pawrad_type), intent(in) :: pawrad
     213              : !Local variables ------------------------------
     214              :  integer  :: i,ierr,info,ldfjac,lr,maxfev,ml,mode,mu,n,nfev,nprint
     215              :  real(dp) :: epsfcn,fac,lmb_temp,upbound,xtol
     216            0 :  real(dp) :: diag(2),fjac(2,2),fkk(lpawu+1),fvec(2),lmb_eps(2)
     217              :  real(dp) :: r(3),qtf(2),wa1(2),wa2(2),wa3(2),wa4(2)
     218              :  character(len=500) :: message
     219              :  !************************************************************************
     220              : 
     221              :  ! Find suitable upper bound for brentq routine
     222            0 :  upbound = five
     223            0 :  do i=1,10
     224              : 
     225            0 :    call compute_slater(lpawu,pawrad,proj2(:),meshsz,upbound,one,fkk(:))
     226            0 :    if (fkk(1) < upawu) exit
     227            0 :    upbound = two * upbound
     228              : 
     229              :  end do ! i
     230              : 
     231            0 :  write(message,'(4a)') "An error occurred when trying to find a suitable lambda and ", &
     232            0 :                      & "epsilon for your input values of upawu and jpawu.", ch10, &
     233            0 :                      & "Either try different values or use dmft_yukawa_lambda and dmft_yukawa_epsilon."
     234              : 
     235            0 :  if (fkk(1) > upawu) ABI_ERROR(message)
     236              : 
     237              :  ! First, set epsilon to 1, and find lambda which yields the correct F0=upawu, to have a good starting point
     238            0 :  call brentq(get_coulomb_u,zero,upbound,two*tol12,four*epsilon(one),100,lmb_temp,ierr)
     239              : 
     240            0 :  if (ierr == 0) ABI_ERROR(message)
     241              : 
     242              :  ! Initial values for lambda and epsilon
     243            0 :  lmb_eps(1) = lmb_temp
     244            0 :  lmb_eps(2) = one
     245              : 
     246            0 :  lambda = lmb_temp
     247            0 :  eps    = one
     248              : 
     249            0 :  if (yukawa_param == 2) return
     250              : 
     251            0 :  if (lpawu > 0) then
     252              : 
     253              :    ! Default values from scipy
     254            0 :    epsfcn = epsilon(one) ; fac = dble(100.) ; n = 2
     255            0 :    ldfjac = n ; lr = n * (n+1) / 2
     256            0 :    maxfev = 200 * (n+1) ; ml = n - 1 ; mode = 1
     257            0 :    mu = n - 1 ; nprint = 0 ; xtol = dble(1.49012e-8)
     258              : 
     259              :    ! Now find lambda and epsilon
     260              :    call hybrd(get_coulomb_uj,2,lmb_eps(:),fvec(:),xtol,maxfev,ml,mu,epsfcn,diag(:),mode, &
     261            0 :             & fac,nprint,info,nfev,fjac(:,:),ldfjac,r(:),lr,qtf(:),wa1(:),wa2(:),wa3(:),wa4(:))
     262              : 
     263            0 :    if (info /= 1) ABI_ERROR(message)
     264              : 
     265              :  end if ! lpawu > 0
     266              : 
     267            0 :  lambda = lmb_eps(1)
     268            0 :  eps    = lmb_eps(2)
     269              : 
     270              :  contains
     271              : 
     272            0 :  subroutine get_coulomb_u(lmb,uu)
     273              : 
     274              : !Arguments ------------------------------------
     275              :  real(dp), intent(in) :: lmb
     276              :  real(dp), intent(out) :: uu
     277              : !Local variables ------------------------------
     278            0 :  real(dp) :: fk(lpawu+1)
     279              : !************************************************************************
     280              : 
     281            0 :  call compute_slater(lpawu,pawrad,proj2(:),meshsz,lmb,one,fk(:))
     282            0 :  uu = fk(1) - upawu
     283              : 
     284            0 :  end subroutine get_coulomb_u
     285              : 
     286            0 :  subroutine get_coulomb_uj(n,lmb_eps,uj,iflag)
     287              : 
     288              : !Arguments ------------------------------------
     289              :  integer, intent(in) :: iflag,n
     290              :  real(dp), intent(in) :: lmb_eps(n)
     291              :  real(dp), intent(inout) :: uj(n)
     292              :  !Local variables ------------------------------
     293              :  real(dp) :: eps,f4of2,f6of2,factor,j2,j4,j6,jh,lmb
     294            0 :  real(dp) :: fk(lpawu+1)
     295              :  character(len=500) :: message
     296              : !************************************************************************
     297              : 
     298              :  ABI_UNUSED(iflag)
     299              : 
     300            0 :  lmb = lmb_eps(1)
     301            0 :  eps = lmb_eps(2)
     302            0 :  call compute_slater(lpawu,pawrad,proj2(:),meshsz,lmb,eps,fk(:))
     303            0 :  uj(1) = fk(1) - upawu
     304              : 
     305            0 :  if (lpawu == 1) then
     306            0 :    j2 = fk(2) * fifth
     307            0 :    jh = j2
     308            0 :  else if (lpawu == 2) then
     309            0 :    f4of2  = dble(0.625)
     310            0 :    factor = (one+f4of2) / dble(14)
     311            0 :    j2 = fk(2)
     312            0 :    j4 = fk(3) / f4of2
     313            0 :    jh = (j2+j4) * factor * half
     314            0 :  else if (lpawu == 3) then
     315            0 :    f4of2  = dble(0.6681)
     316            0 :    f6of2  = dble(0.4943)
     317            0 :    factor = (dble(286.)+dble(195.)*f4of2+dble(250.)*f6of2) / dble(6435.)
     318            0 :    j2 = fk(2)
     319            0 :    j4 = fk(3) / f4of2
     320            0 :    j6 = fk(4) / f6of2
     321            0 :    jh = (j2+j4+j6) * factor * third
     322              :  else
     323            0 :    write(message,'(a,i0,2a)') ' lpawu=',lpawu,ch10,' lpawu not equal to 0, 1, 2 or 3 is not allowed'
     324            0 :    ABI_ERROR(message)
     325              :  end if ! lpawu
     326              : 
     327            0 :  uj(2) = jh - jpawu
     328              : 
     329            0 :  end subroutine get_coulomb_uj
     330              : 
     331              :  end subroutine get_lambda
     332              : !!***
     333              : 
     334              : !----------------------------------------------------------------------
     335              : 
     336              : END MODULE m_paw_yukawa
     337              : !!***
        

Generated by: LCOV version 2.3-1