LCOV - code coverage report
Current view: top level - src/62_poisson - m_vcoul.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 60.9 % 700 426
Test Date: 2026-09-19 15:24:51 Functions: 60.7 % 28 17

            Line data    Source code
       1              : !!****m* ABINIT/m_vcoul
       2              : !! NAME
       3              : !!  m_vcoul
       4              : !!
       5              : !! FUNCTION
       6              : !!  This module contains the definition of the vcoul_t as well
       7              : !!  as procedures to calculate the Coulomb interaction in reciprocal space
       8              : !!  taking into account a possible cutoff in real space.
       9              : !!  Procedures to deal with the singularity for q --> 0 are also provided.
      10              : !!
      11              : !! COPYRIGHT
      12              : !! Copyright (C) 1999-2026 ABINIT group (MG, FB)
      13              : !! This file is distributed under the terms of the
      14              : !! GNU General Public License, see ~abinit/COPYING
      15              : !! or http://www.gnu.org/copyleft/gpl.txt .
      16              : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      17              : !!
      18              : !! SOURCE
      19              : 
      20              : #if defined HAVE_CONFIG_H
      21              : #include "config.h"
      22              : #endif
      23              : 
      24              : #include "abi_common.h"
      25              : 
      26              : module m_vcoul
      27              : 
      28              :  use defs_basis
      29              :  use m_abicore
      30              :  use m_errors
      31              :  use m_xmpi
      32              :  use m_splines
      33              :  use m_sort
      34              : 
      35              :  use m_fstrings,        only : sjoin, itoa
      36              :  use m_special_funcs,   only : abi_derf
      37              :  use m_bessel,          only : calck0
      38              :  use m_io_tools,        only : open_file
      39              :  use m_gwdefs,          only : GW_TOLQ0
      40              :  use m_numeric_tools,   only : arth, geop, imin_loc, llsfit_svd, l2norm, OPERATOR(.x.), quadrature, isdiagmat
      41              :  use m_hide_lapack,     only : matrginv
      42              :  use m_geometry,        only : normv, metric
      43              :  use m_qplusg,          only : cmod_qpg
      44              :  use m_crystal,         only : crystal_t
      45              :  use m_bz_mesh,         only : kmesh_t
      46              :  use m_gsphere,         only : gsphere_t
      47              :  use m_fftcore,         only : get_kg
      48              :  use m_dtfil,           only : isfile
      49              : 
      50              :  ! Cut-off methods modules
      51              :  use m_cutoff_sphere,   only : cutoff_sphere
      52              :  use m_cutoff_slab,     only : cutoff_slab
      53              :  use m_cutoff_cylinder, only : cutoff_cylinder
      54              : 
      55              :  implicit none
      56              : 
      57              :  public :: gw_icutcoul_to_mode
      58              :  public :: carrier_isz
      59              : 
      60              :  private
      61              : !!***
      62              : 
      63              : !!****t* m_vcoul/vcoul_t
      64              : !! NAME
      65              : !!  vcoul_t
      66              : !!
      67              : !! FUNCTION
      68              : !!  This data type contains the square root of the Fourier components of the Coulomb interaction
      69              : !!  calculated taking into account a possible cutoff. It also stores info on the particular geometry
      70              : !!  used for the cutoff as well as quantities required to deal with the Coulomb divergence for q --> 0.
      71              : !!
      72              : !! SOURCE
      73              : 
      74              : type,public :: vcoul_t
      75              : 
      76              :   integer :: ng = -1
      77              :    ! Number of G-vectors
      78              : 
      79              :   integer :: nqibz = -1
      80              :    ! Number of irreducible q-points
      81              : 
      82              :   integer :: nqlwl = -1
      83              :    ! Number of small q-points around Gamma
      84              : 
      85              :   real(dp) :: alpha(3) = -one
      86              :    ! Length of the finite slab
      87              : 
      88              :   real(dp) :: rcut = -one
      89              :    ! Cutoff radius.
      90              : 
      91              :   real(dp) :: i_sz = huge(one)
      92              :    ! Value of the integration of the Coulomb singularity 4\pi/V_BZ \int_BZ d^3q 1/q^2
      93              : 
      94              :   real(dp) :: i_sz_resid = huge(one)
      95              :    ! Residual difference between the i_sz in the sigma self-energy for exchange,
      96              :    ! and the i_sz already present in the generalized Kohn-Sham eigenenergies
      97              :    ! Initialized to the same value as i_sz
      98              : 
      99              :   real(dp) :: hcyl = -one
     100              :    ! Length of the finite cylinder along the periodic dimension
     101              : 
     102              :   real(dp) :: ucvol = -one
     103              :     ! Volume of the unit cell
     104              : 
     105              :   character(len=50) :: mode
     106              :    ! String defining the cutoff mode, possible values are: sphere,cylinder,slab,crystal
     107              : 
     108              :   integer :: pdir(3)
     109              :    ! 1 if the system is periodic along this direction
     110              : 
     111              :   real(dp) :: boxcenter(3) = -1
     112              :    ! 1 if the point in inside the cutoff region 0 otherwise
     113              :    ! Reduced coordinates of the center of the box (input variable)
     114              : 
     115              :   real(dp) :: vcutgeo(3) = huge(one)
     116              :    ! For each reduced direction gives the length of the finite system
     117              :    ! 0 if the system is infinite along this direction.
     118              :    ! negative values indicate that a finite size has to be used.
     119              : 
     120              :   real(dp) :: rprimd(3,3) = zero
     121              :    ! Lattice vectors in real space.
     122              : 
     123              :   real(dp),allocatable :: qibz(:,:)
     124              :    ! (3, nqibz)
     125              :    ! q-points in the IBZ.
     126              : 
     127              :   real(dp),allocatable :: qlwl(:,:)
     128              :    ! (3, nqlwl)
     129              :    ! q-points for the treatment of the Coulomb singularity.
     130              : 
     131              :   complex(gwp),allocatable :: vc_sqrt(:,:)
     132              :    ! (ng, nqibz)
     133              :    ! Square root of the Coulomb interaction in reciprocal space.
     134              :    ! complex-valued to allow for a possible cutoff (Rozzi's method)
     135              : 
     136              :   complex(gwp),allocatable :: vcqlwl_sqrt(:,:)
     137              :    ! (ng, nqlwl)
     138              :    ! Square root of the Coulomb term calculated for small q-points
     139              : 
     140              :   complex(gwp),allocatable :: vc_sqrt_resid(:,:)
     141              :    ! (ng, nqibz)
     142              :    ! Square root of the residual difference between the Coulomb interaction in the sigma self-energy for exchange,
     143              :    ! and the Coulomb interaction already present in the generalized Kohn-Sham eigenenergies (when they come from an hybrid)
     144              :    ! Given in reciprocal space. At the call to vcoul_init, it is simply initialized at the value of vc_sqrt(:,:),
     145              :    ! and only later modified. A cutoff might be applied.
     146              : 
     147              : contains
     148              :    procedure :: init => vcoul_init    ! Main creation method.
     149              :    procedure :: plot => vcoul_plot    ! Plot vc in real and reciprocal space.
     150              :    procedure :: print => vcoul_print  ! Print info on the object.
     151              :    procedure :: free => vcoul_free    ! Free memory
     152              : end type vcoul_t
     153              : !!***
     154              : 
     155              : !!****t* m_vcoul/mc_t
     156              : !! NAME
     157              : !!  mc_t
     158              : !!
     159              : !! FUNCTION
     160              : !! Mimicking the BerkeleyGW technique
     161              : !! A Monte-Carlo sampling of each miniBZ surrounding each (q+G) point.
     162              : !! However:
     163              : !!    - extended to multiple shifts
     164              : !!    - with an adaptative number of MonteCarlo sampling points
     165              : !!
     166              : !! SOURCE
     167              : 
     168              : type, public :: mc_t
     169              : 
     170              :   integer :: nmc_max = -1
     171              : 
     172              :   real(dp) :: q0sph = -one
     173              : 
     174              :   real(dp) :: ucvol = -one
     175              : 
     176              :   real(dp) :: gmet(3,3) = -one
     177              : 
     178              :   real(dp),allocatable :: qran(:,:)
     179              :   ! (3, nmc_max)
     180              : 
     181              : contains
     182              :   procedure :: init => mc_init
     183              :   procedure :: integrate => mc_integrate
     184              :   procedure :: free => mc_free
     185              : end type mc_t
     186              : !!***
     187              : 
     188              : !!****t* m_vcoul/vcgen_t
     189              : !! NAME
     190              : !!  vcgen_t
     191              : !!
     192              : !! FUNCTION
     193              : !!
     194              : !! SOURCE
     195              : 
     196              : type, public :: vcgen_t
     197              : 
     198              :   integer :: nkbz = -1
     199              :    ! Number of k-points in full BZ.
     200              : 
     201              :   integer :: opt_cylinder
     202              : 
     203              :   integer :: opt_slab
     204              : 
     205              :   real(dp) :: alpha(3) = -one
     206              :    ! Lenght of the finite surface.
     207              : 
     208              :   real(dp) :: rcut = -one
     209              :    ! Cutoff radius.
     210              : 
     211              :   real(dp) :: hcyl = -one
     212              :    ! Length of the finite cylinder along the periodic dimension
     213              : 
     214              :   character(len=50) :: mode
     215              :    ! String defining the cutoff mode
     216              : 
     217              :   integer :: pdir(3)
     218              :    ! 1 if the system is periodic along this direction
     219              : 
     220              :   real(dp) :: boxcenter(3) = -1
     221              :    ! 1 if the point in inside the cutoff region 0 otherwise
     222              :    ! Reduced coordinates of the center of the box (input variable)
     223              : 
     224              :   real(dp) :: vcutgeo(3) = huge(one)
     225              :    ! For each reduced direction gives the length of the finite system
     226              :    ! 0 if the system is infinite along this direction.
     227              :    ! negative values indicate that a finite size has to be used.
     228              : 
     229              :   real(dp) :: i_sz = huge(one)
     230              :    ! Value of the integration of the Coulomb singularity 4\pi/V_BZ \int_BZ d^3q 1/q^2
     231              : 
     232              :   type(mc_t) :: mc
     233              :    ! Monte carlo integrator.
     234              : 
     235              : contains
     236              :   procedure :: init => vcgen_init                  ! Initialize the object
     237              :   procedure :: get_vc_sqrt => vcgen_get_vc_sqrt    ! Compute sqrt(vc(q,g))
     238              :   procedure :: free => vcgen_free                  ! Free memory
     239              :   procedure :: print => vcgen_print                ! Print info on the object.
     240              : end type vcgen_t
     241              : !!***
     242              : 
     243              :  ! private stuff
     244              :  real(dp),parameter :: TOLQ0 = 1.d-3
     245              : 
     246              : CONTAINS  !========================================================================================
     247              : !!***
     248              : 
     249              : !!****f* m_vcoul/gw_icutcoul_to_mode
     250              : !! NAME
     251              : !! gw_icutcoul_to_mode
     252              : !!
     253              : !! FUNCTION
     254              : !! Convert gw_icutcoul_to_mode to mode string.
     255              : !!
     256              : !! SOURCE
     257              : 
     258          404 : subroutine gw_icutcoul_to_mode(gw_icutcoul, mode)
     259              : 
     260              : !Arguments ------------------------------------
     261              :  integer,intent(in) :: gw_icutcoul
     262              :  character(len=*),intent(out) :: mode
     263              : ! *************************************************************************
     264              : 
     265          404 :  mode = 'NONE'
     266          404 :  if (gw_icutcoul == 0) mode = 'SPHERE'
     267          404 :  if (gw_icutcoul == 1) mode = 'CYLINDER'
     268          404 :  if (gw_icutcoul == 2) mode = 'SLAB'
     269          404 :  if (gw_icutcoul == 3) mode = 'CRYSTAL'
     270          404 :  if (gw_icutcoul == 4) mode = 'ERF'
     271          404 :  if (gw_icutcoul == 5) mode = 'ERFC'
     272          404 :  if (gw_icutcoul == 6) mode = 'AUXILIARY_FUNCTION'
     273          404 :  if (gw_icutcoul == 7) mode = 'AUX_GB'
     274          404 :  if (gw_icutcoul == 14) mode = 'MINIBZ-ERF'
     275          404 :  if (gw_icutcoul == 15) mode = 'MINIBZ-ERFC'
     276          404 :  if (gw_icutcoul == 16) mode = 'MINIBZ'
     277              : 
     278          404 : end subroutine gw_icutcoul_to_mode
     279              : !!***
     280              : 
     281              : !!****f* m_vcoul/vcoul_init
     282              : !! NAME
     283              : !! vcoul_init
     284              : !!
     285              : !! FUNCTION
     286              : !! Perform general check and initialize the data type containing information on the cutoff technique
     287              : !! Note %vc_sqrt_resid and %i_sz_resid are simply initialized at the same value as %vc_sqrt and %i_sz
     288              : !!
     289              : !! INPUTS
     290              : !!  Gsph=Info of the G sphere.
     291              : !!  Qmesh=Info on the q-point sampling.
     292              : !!  Kmesh=Info on the k-point sampling.
     293              : !!  rcut=Cutoff radius for the cylinder.
     294              : !!  gw_icutcoul=Option of the cutoff technique.
     295              : !!  vcutgeo(3)= Info on the orientation and extension of the cutoff region.
     296              : !!  ng=Number of G-vectors to be used to describe the Coulomb interaction
     297              : !!  nqlwl=Number of point around Gamma for treatment of long-wavelength limit
     298              : !!  qlwl(3,nqlwl)= The nqlwl "small" q-points
     299              : !!  comm=MPI communicator.
     300              : !!
     301              : !! SOURCE
     302              : 
     303          404 : subroutine vcoul_init(vcp, Gsph, Cryst, Qmesh, Kmesh, rcut, gw_icutcoul, vcutgeo, vc_ecut, ng, nqlwl, qlwl, comm)
     304              : 
     305              : !Arguments ------------------------------------
     306              : !scalars
     307              :  class(vcoul_t),intent(out) :: vcp
     308              :  integer,intent(in) :: ng,nqlwl, gw_icutcoul, comm
     309              :  real(dp),intent(in) :: rcut, vc_ecut
     310              :  type(kmesh_t),target,intent(in) :: Kmesh, Qmesh
     311              :  type(gsphere_t),target,intent(in) :: Gsph
     312              :  type(crystal_t),intent(in) :: Cryst
     313              : !arrays
     314              :  real(dp),intent(in) :: qlwl(3,nqlwl),vcutgeo(3)
     315              : 
     316              : !Local variables-------------------------------
     317              : !scalars
     318              :  integer,parameter :: master=0
     319              :  integer :: nqibz, nqbz, nkbz, iqlwl, iq_ibz, opt_cylinder,my_rank,nprocs, opt_slab
     320              :  real(dp) :: bz_geometry_factor,q0_vol, rcut2
     321              :  character(len=500) :: msg
     322         5252 :  type(mc_t) :: mc
     323              : !arrays
     324              :  integer :: units(2)
     325          404 :  integer, contiguous, pointer :: gvec(:,:)
     326              :  real(dp) :: a1(3),a2(3),a3(3),b1(3),b2(3),b3(3)
     327          404 :  real(dp),allocatable :: vcoul(:,:),vcoul_lwl(:,:)
     328          404 :  real(dp),contiguous, pointer :: qibz(:,:), qbz(:,:)
     329              : ! *************************************************************************
     330              : 
     331              :  !call wrtout(std_out, "in vcoul_init")
     332          404 :  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
     333         1212 :  units = [std_out, ab_out]
     334              : 
     335          404 :  nqibz = qmesh%nibz; nqbz = qmesh%nbz
     336          404 :  qibz => qmesh%ibz; qbz => qmesh%bz
     337          404 :  nkbz = kmesh%nbz
     338              : 
     339              :  ! Save dimension and other useful quantities in vcp
     340          404 :  vcp%ng        = ng                   ! Number of G-vectors in the Coulomb matrix elements.
     341          404 :  vcp%nqibz     = nqibz                ! Number of irred q-point.
     342          404 :  vcp%nqlwl     = nqlwl                ! Number of small q-directions to deal with singularity and non Analytic behavior.
     343          404 :  vcp%rcut      = rcut                 ! Cutoff radius for cylinder.
     344          404 :  vcp%hcyl      = zero                 ! Length of finite cylinder (Rozzi"s method, default is Beigi).
     345          404 :  vcp%ucvol     = cryst%ucvol          ! Unit cell volume.
     346         5252 :  vcp%rprimd    = Cryst%rprimd(:,:)    ! Dimensional direct lattice.
     347         1616 :  vcp%boxcenter = zero                 ! Boxcenter at the moment is supposed to be at the origin.
     348         1616 :  vcp%vcutgeo   = vcutgeo(:)           ! Info on the orientation and extension of the cutoff region.
     349              : 
     350          404 :  gvec => Gsph%gvec
     351              : 
     352          404 :  call gw_icutcoul_to_mode(gw_icutcoul, vcp%mode)
     353              : 
     354         1212 :  ABI_MALLOC(vcp%qibz, (3, nqibz))
     355        11072 :  vcp%qibz = Qmesh%ibz(:,:)
     356         1212 :  ABI_MALLOC(vcp%qlwl, (3, nqlwl))
     357         2424 :  vcp%qlwl = qlwl(:,:)
     358              : 
     359              :  ! ===============================================
     360              :  ! == Calculation of the FT of the Coulomb term ==
     361              :  ! ===============================================
     362              :  a1 = cryst%rprimd(:,1); a2 = cryst%rprimd(:,2); a3 = cryst%rprimd(:,3)
     363              :  b1 = two_pi * cryst%gprimd(:,1); b2 = two_pi * cryst%gprimd(:,2); b3 = two_pi * cryst%gprimd(:,3)
     364              : 
     365         1616 :  ABI_MALLOC(vcoul    , (ng, nqibz))
     366         1616 :  ABI_MALLOC(vcoul_lwl, (ng, nqlwl))
     367              : 
     368          407 :  select case (trim(vcp%mode))
     369              :  case ('MINIBZ', 'MINIBZ-ERFC', 'MINIBZ-ERF')
     370            3 :    call mc%init(cryst%rprimd, cryst%ucvol, cryst%gprimd, cryst%gmet, kmesh%kptrlatt)
     371              : 
     372            3 :    rcut2 = vcp%rcut**2
     373           12 :    do iq_ibz=1,nqibz
     374           12 :      call mc%integrate(vcp%mode, qibz(:, iq_ibz), ng, gvec, rcut2, nkbz, vcoul(:, iq_ibz), comm)
     375              :    end do
     376              : 
     377              :    ! Treat the limit q --> 0
     378            3 :    vcp%i_sz = vcoul(1, 1)
     379              : 
     380            6 :    do iqlwl=1,nqlwl
     381            6 :      call mc%integrate(vcp%mode, qlwl(:, iqlwl), ng, gvec, rcut2, nkbz, vcoul_lwl(:, iqlwl), comm)
     382              :    end do
     383              : 
     384            3 :    call mc%free()
     385              : 
     386              :  case ('SPHERE')
     387              :    ! A non-positive value of rcut activates the recipe of Spencer & Alavi, PRB 77, 193110 (2008) [[cite:Spencer2008]].
     388           46 :    if (vcp%rcut < tol12) then
     389           10 :      vcp%rcut = (cryst%ucvol * nkbz * 3.d0 / four_pi) ** third
     390           10 :      write(msg,'(2a,2x,f8.4,a)')ch10,' Using calculated rcut: ',vcp%rcut,' to have same volume as the BvK crystal'
     391           10 :      call wrtout(std_out, msg)
     392              :    end if
     393          184 :    vcp%vcutgeo = zero
     394              : 
     395          137 :    do iq_ibz=1,nqibz
     396          137 :      call cutoff_sphere(qibz(:,iq_ibz), ng, gvec, cryst%gmet, vcp%rcut, vcoul(:,iq_ibz))
     397              :    end do
     398              : 
     399              :    ! q-points for optical limit.
     400           92 :    do iqlwl=1,nqlwl
     401           92 :      call cutoff_sphere(qlwl(:,iqlwl), ng, gvec, cryst%gmet, vcp%rcut, vcoul_lwl(:,iqlwl))
     402              :    end do
     403              : 
     404              :    ! Treat the limit q --> 0
     405              :    ! The small cube is approximated by a sphere, while vc(q=0) = 2piR**2.
     406              :    ! if a single q-point is used, the expression for the volume is exact.
     407           46 :    vcp%i_sz = two_pi * vcp%rcut**2
     408              : 
     409              :  case ('CYLINDER')
     410            2 :    call cylinder_setup(cryst, vcp%vcutgeo, vcp%hcyl, vcp%pdir, opt_cylinder)
     411              : 
     412           12 :    do iq_ibz=1,nqibz
     413              :      call cutoff_cylinder(qibz(:,iq_ibz), ng, gvec, vcp%rcut, vcp%hcyl, vcp%pdir,&
     414           12 :                           vcp%boxcenter, Cryst%rprimd, vcoul(:,iq_ibz), opt_cylinder, comm)
     415              :    end do
     416              : 
     417              :    ! q-points for optical limit.
     418            4 :    do iqlwl=1,nqlwl
     419              :      call cutoff_cylinder(qlwl(:,iqlwl), ng, gvec, vcp%rcut, vcp%hcyl, vcp%pdir,&
     420            4 :                           vcp%boxcenter, Cryst%rprimd, vcoul_lwl(:,iqlwl), opt_cylinder, comm)
     421              :    end do
     422              : 
     423              :    ! If Beigi, treat the limit q --> 0.
     424            2 :    if (opt_cylinder == 1) then
     425            1 :      call beigi_cylinder_limit(opt_cylinder, cryst, nqibz, nkbz, vcp%rcut, vcp%hcyl, vcp%boxcenter, vcp%pdir, vcp%i_sz)
     426              :    else
     427              :      ! In Rozzi's method the lim q+G --> 0 is finite.
     428            1 :      vcp%i_sz = vcoul(1,1)
     429              :    end if
     430              : 
     431              :  case ('SLAB')
     432            0 :    call surface_setup(cryst, vcp%vcutgeo, vcp%alpha, vcp%rcut, vcp%pdir, opt_slab)
     433              : 
     434            0 :    do iq_ibz=1,nqibz
     435              :      call cutoff_slab(qibz(:,iq_ibz), ng, gvec, cryst%gprimd, vcp%rcut, &
     436            0 :                       vcp%boxcenter, vcp%pdir, vcp%alpha, vcoul(:,iq_ibz), opt_slab)
     437              :    end do
     438              : 
     439              :    ! q-points for optical limit.
     440            0 :    do iqlwl=1,nqlwl
     441              :      call cutoff_slab(qlwl(:,iq_ibz), ng, gvec, cryst%gprimd, vcp%rcut, &
     442            0 :                       vcp%boxcenter, vcp%pdir, vcp%alpha, vcoul_lwl(:,iqlwl), opt_slab)
     443              :    end do
     444              : 
     445              :    ! If Beigi, treat the limit q --> 0.
     446            0 :    if (opt_slab == 1) then
     447              :      ! Integrate numerically in the plane close to 0
     448              :      call beigi_surface_limit(opt_slab, cryst, nqibz, nkbz, vcp%rcut, vcp%alpha, &
     449            0 :                               vcp%boxcenter, vcp%pdir, vcp%i_sz)
     450              :    else
     451              :      ! In Rozzi's method the lim q+G --> 0 is finite.
     452            0 :      vcp%i_sz=vcoul(1,1)
     453              :    end if
     454              : 
     455              :  case ('CRYSTAL', 'AUXILIARY_FUNCTION', "AUX_GB")
     456         2662 :    do iq_ibz=1,nqibz
     457         2328 :      call cmod_qpg(nqibz, iq_ibz, qibz, ng, gvec, cryst%gprimd, vcoul(:,iq_ibz))
     458              : 
     459         2662 :      if (iq_ibz == 1) then
     460              :        ! The singularity is treated using vcoul_lwl.
     461          334 :        vcoul(1, iq_ibz) = zero
     462        45452 :        vcoul(2:,iq_ibz) = four_pi / vcoul(2:,iq_ibz)**2
     463              :      else
     464       219536 :        vcoul(:,iq_ibz) = four_pi / vcoul(:,iq_ibz)**2
     465              :      end if
     466              :    end do ! iq_ibz
     467              : 
     468              :    ! q-points for optical limit.
     469          668 :    do iqlwl=1,nqlwl
     470          668 :      call cmod_qpg(nqlwl, iqlwl, qlwl, ng, gvec, cryst%gprimd, vcoul_lwl(:,iqlwl))
     471              :    end do
     472        46120 :    vcoul_lwl = four_pi/vcoul_lwl**2
     473              : 
     474              :    ! Treatment of 1/q^2 singularity
     475              : 
     476          334 :    if (vcp%mode == "CRYSTAL") then
     477              :      ! Analytic integration of 4pi/q^2 over the volume element:
     478              :      ! $4pi/V \int_V d^3q 1/q^2 =4pi bz_geometric_factor V^(-2/3)$
     479              :      ! i_sz=4*pi*bz_geometry_factor*q0_vol**(-two_thirds) where q0_vol= V_BZ/N_k
     480              :      ! bz_geometry_factor: sphere=7.79, fcc=7.44, sc=6.188, bcc=6.946, wz=5.255 (see gwa.pdf, appendix A.4)
     481          117 :      q0_vol = (two_pi) **3 / (nkbz*cryst%ucvol); bz_geometry_factor=zero
     482          117 :      vcp%i_sz = four_pi*7.44*q0_vol**(-two_thirds)
     483              : 
     484          217 :    else if (vcp%mode == "AUXILIARY_FUNCTION") then
     485              :      ! Numerical integration of the exact-exchange divergence through the
     486              :      ! auxiliary function of Carrier et al. PRB 75, 205126 (2007) [[cite:Carrier2007]].
     487          209 :      vcp%i_sz = carrier_isz(cryst, nqbz, qbz, rcut, comm)
     488              : 
     489            8 :    else if (vcp%mode == "AUX_GB") then
     490              :      ! We use the auxiliary function of a Gygi-Baldereschi variant [[cite:Gigy1986]]
     491            8 :      vcp%i_sz = gygi_baldereschi_isz(cryst, nqbz, qbz, vc_ecut, ng, gvec)
     492              : 
     493              :    else
     494            0 :      ABI_ERROR(sjoin("Need treatment of 1/q^2 singularity! for mode", vcp%mode))
     495              :    end if
     496              : 
     497              :  case ('ERF')
     498              :    ! Modified long-range only Coulomb interaction thanks to the error function:
     499              :    ! * Vc = erf(r/rcut)/r
     500              :    ! * The singularity is treated using vcoul_lwl.
     501            4 :    do iq_ibz=1,nqibz
     502            3 :      call cmod_qpg(nqibz, iq_ibz, qibz, ng, gvec, cryst%gprimd, vcoul(:,iq_ibz))
     503              : 
     504              :      ! The Fourier transform of the error function reads
     505            4 :      if (iq_ibz == 1) then
     506            1 :        vcoul(1, iq_ibz) = zero
     507          137 :        vcoul(2:,iq_ibz) = four_pi/(vcoul(2:,iq_ibz)**2) *  EXP( -0.25d0 * (vcp%rcut*vcoul(2:,iq_ibz))**2 )
     508              :      else
     509          276 :        vcoul(:,iq_ibz)  = four_pi/(vcoul(:, iq_ibz)**2) *  EXP( -0.25d0 * (vcp%rcut*vcoul(: ,iq_ibz))**2 )
     510              :      end if
     511              :    end do
     512              : 
     513              :    ! q-points for optical limit.
     514            2 :    do iqlwl=1,nqlwl
     515            2 :      call cmod_qpg(nqlwl, iqlwl, qlwl, ng, gvec, cryst%gprimd, vcoul_lwl(:,iqlwl))
     516              :    end do
     517          139 :    vcoul_lwl = four_pi/(vcoul_lwl**2) *  EXP( -0.25d0 * (vcp%rcut*vcoul_lwl)**2 )
     518              : 
     519              :    ! === Treat 1/q^2 singularity ===
     520              :    ! * We use the auxiliary function from PRB 75, 205126 (2007) [[cite:Carrier2007]]
     521            1 :    vcp%i_sz = carrier_isz(cryst, nqbz, qbz, rcut, comm)
     522              : 
     523              :  case ('ERFC')
     524              :    ! * Use a modified short-range only Coulomb interaction thanks to the complementary error function:
     525              :    !   $ V_c = [1-erf(r/r_{cut})]/r $
     526              :    ! * The Fourier transform of the error function reads
     527              :    !   vcoul=four_pi/(vcoul**2) * ( 1.d0 - exp( -0.25d0 * (vcp%rcut*vcoul)**2 ) )
     528          143 :    do iq_ibz=1,nqibz
     529          125 :      call cmod_qpg(nqibz, iq_ibz, qibz,ng, gvec, cryst%gprimd, vcoul(:,iq_ibz))
     530              : 
     531          143 :      if (iq_ibz == 1) then
     532           18 :        vcoul(1 ,iq_ibz) = zero
     533         1602 :        vcoul(2:,iq_ibz) = four_pi/(vcoul(2:,iq_ibz)**2) * ( one - EXP( -0.25d0 * (vcp%rcut*vcoul(2:,iq_ibz))**2 ) )
     534              :      else
     535        10446 :        vcoul(:, iq_ibz) = four_pi/(vcoul(:, iq_ibz)**2) * ( one - EXP( -0.25d0 * (vcp%rcut*vcoul(:, iq_ibz))**2 ) )
     536              :      end if
     537              :    end do ! iq_ibz
     538              : 
     539              :    ! q-points for optical limit.
     540           36 :    do iqlwl=1,nqlwl
     541           36 :      call cmod_qpg(nqlwl, iqlwl, qlwl, ng, gvec, cryst%gprimd, vcoul_lwl(:,iqlwl))
     542              :    end do
     543         1638 :    vcoul_lwl = four_pi/(vcoul_lwl**2) * ( one - EXP( -0.25d0 * (vcp%rcut*vcoul_lwl)**2 ) )
     544              : 
     545              :    ! === Treat 1/q^2 singularity ===
     546              :    ! * There is NO singularity in this case.
     547           18 :    vcp%i_sz = pi * vcp%rcut**2 ! Final result stored here
     548              : 
     549              :  case default
     550          404 :    ABI_BUG(sjoin('Unsupported cutoff mode:', vcp%mode))
     551              :  end select
     552              : 
     553              :  !call wrtout(std_out, sjoin("vcp%i_sz", ftoa(vcp%i_sz)))
     554          404 :  vcp%i_sz_resid = vcp%i_sz
     555              : 
     556              :  ! Store final results in complex array as Rozzi's cutoff can give real negative values
     557         1616 :  ABI_MALLOC(vcp%vc_sqrt, (ng, nqibz))
     558         1212 :  ABI_MALLOC(vcp%vc_sqrt_resid, (ng, nqibz))
     559       356380 :  vcp%vc_sqrt = CMPLX(vcoul, zero)
     560       355976 :  vcp%vc_sqrt = SQRT(vcp%vc_sqrt)
     561       356380 :  vcp%vc_sqrt_resid = vcp%vc_sqrt
     562          404 :  ABI_FREE(vcoul)
     563              : 
     564         1616 :  ABI_MALLOC(vcp%vcqlwl_sqrt, (ng, nqlwl))
     565       120488 :  vcp%vcqlwl_sqrt = CMPLX(vcoul_lwl, zero)
     566       120084 :  vcp%vcqlwl_sqrt = SQRT(vcp%vcqlwl_sqrt)
     567          404 :  ABI_FREE(vcoul_lwl)
     568              : 
     569          404 :  call vcp%print(units)
     570              :  !call wrtout(std_out, " exiting vcoul_init")
     571              : 
     572         1212 : end subroutine vcoul_init
     573              : !!***
     574              : 
     575              : 
     576              : !!****f* m_vcoul/cylinder_setup
     577              : !! NAME
     578              : !!  cylinder_setup
     579              : !!
     580              : !! FUNCTION
     581              : !!
     582              : !! SOURCE
     583              : 
     584            2 : subroutine cylinder_setup(cryst, vcutgeo, hcyl, pdir, opt_cylinder)
     585              : 
     586              :  type(crystal_t),intent(in) :: cryst
     587              :  real(dp),intent(in) :: vcutgeo(3)
     588              :  real(dp),intent(out) :: hcyl
     589              :  integer,intent(out) :: pdir(3), opt_cylinder
     590              : 
     591              : !Local variables-------------------------------
     592              :  integer :: ii
     593              :  real(dp),parameter :: tol999 = 999.0
     594              :  real(dp) :: check
     595              : ! *************************************************************************
     596              : 
     597            8 :  ABI_CHECK(count(abs(vcutgeo) > tol6) == 1, 'Wrong cutgeo for cylinder')
     598              : 
     599              :  ! Beigi's method is the default one, i.e infinite cylinder of radius rcut.
     600              :  ! Use negative values to use Rozzi's method with finite cylinder of extent hcyl.
     601            2 :  opt_cylinder = 1; hcyl = zero; pdir(:) = 0
     602            8 :  do ii=1,3
     603            6 :    check = vcutgeo(ii)
     604            8 :    if (abs(check) > tol6) then
     605            2 :      pdir(ii) = 1
     606            2 :      if (check < zero) then
     607              :        ! use Rozzi's method.
     608            4 :        hcyl = ABS(check) * NORM2(cryst%rprimd(:,ii))
     609            1 :        opt_cylinder = 2
     610              :        ! Check to enter the infinite Rozzi treatment
     611            1 :        if(vcutgeo(3) <= -tol999) hcyl = tol12
     612              :      end if
     613              :    end if
     614              :  end do
     615              : 
     616            8 :  ABI_CHECK((count(pdir == 1) == 1), 'Wrong pdir for cylinder')
     617            2 :  if (pdir(3) /= 1) then
     618            0 :    ABI_ERROR("The cylinder must be along the z-axis")
     619              :  end if
     620              : 
     621            2 : end subroutine cylinder_setup
     622              : !!***
     623              : 
     624              : !!****f* m_vcoul/surface_setup
     625              : !! NAME
     626              : !!  surface_setup
     627              : !!
     628              : !! FUNCTION
     629              : !!
     630              : !! SOURCE
     631              : 
     632            0 : subroutine surface_setup(cryst, vcutgeo, alpha, rcut, pdir, opt_slab)
     633              : 
     634              :  type(crystal_t),intent(in) :: cryst
     635              :  real(dp),intent(in) :: vcutgeo(3)
     636              :  real(dp),intent(out) :: alpha(3)
     637              :  real(dp),intent(inout) :: rcut
     638              :  integer,intent(out) :: pdir(3), opt_slab
     639              : 
     640              : !Local variables-------------------------------
     641              :  integer :: ii
     642              :  real(dp) :: check
     643              :  character(len=500) :: msg
     644              : ! *************************************************************************
     645              : 
     646            0 :  ABI_CHECK(count(vcutgeo /= zero) == 2, "Wrong vcutgeo")
     647              : 
     648              :  ! Default is Beigi's method.
     649            0 :  opt_slab = 1; if (any(vcutgeo < zero)) opt_slab = 2
     650            0 :  pdir(:) = zero; alpha(:)=zero
     651            0 :  do ii=1,3
     652            0 :    check = vcutgeo(ii)
     653            0 :    if (abs(check) > zero) then
     654              :      ! Use Rozzi's method with a finite surface along x-y
     655            0 :      pdir(ii) = 1
     656            0 :      if (check < zero) alpha(ii) = normv(check * cryst%rprimd(:,ii), cryst%rmet, 'R')
     657              :    end if
     658              :  end do
     659              : 
     660              :  ! In Beigi's method, the surface must be along x-y and R must be L_Z/2.
     661            0 :  if (opt_slab == 1) then
     662            0 :    msg = "2D Beigi method, the periodicity must be in the x-y plane. Modify vcutgeo and/or your geometry."
     663            0 :    ABI_CHECK(all(pdir == [1, 1, 0]), msg)
     664            0 :    rcut = half*SQRT(DOT_PRODUCT(cryst%rprimd(:,3), cryst%rprimd(:,3)))
     665              :  end if
     666              : 
     667            0 : end subroutine surface_setup
     668              : !!***
     669              : 
     670              : !!****f* m_vcoul/integratefaux
     671              : !! NAME
     672              : !!  integratefaux
     673              : !!
     674              : !! FUNCTION
     675              : !!
     676              : !! SOURCE
     677              : 
     678          420 : real(dp) function integratefaux(rcut, gprimd, ucvol, comm)
     679              : 
     680              :  real(dp),intent(in) :: rcut, gprimd(3,3), ucvol
     681              :  integer,intent(in) :: comm
     682              : 
     683              : !Local variables-------------------------------
     684              :  integer,parameter :: nref = 3, nq = 50
     685              :  integer :: ierr,iq,iqx1,iqy1,iqz1,iqx2,iqy2,iqz2,miniqy1,maxiqy1,nqhalf, nprocs, my_rank
     686              :  real(dp) :: invnq,invnq3,qq,weightq,weightxy,weightxyz
     687              :  real(dp) :: qq1(3),qq2(3),bb4sinpiqq_2(3,nq),sin2piqq(nq),bb4sinpiqq2_2(3,0:nq),sin2piqq2(3,0:nq)
     688              :  real(dp) :: b1(3), b2(3), b3(3), bb(3)
     689              :  real(dp) :: b1b1,b2b2,b3b3,b1b2,b2b3,b3b1
     690              : ! *************************************************************************
     691              : 
     692              :  ! nq is the number of sampling points along each axis for the numerical integration
     693              :  ! nref is the area where the mesh is refined
     694              : 
     695          210 :  integratefaux = zero
     696          210 :  invnq = one/DBLE(nq)
     697          210 :  invnq3 = invnq**3
     698          210 :  nqhalf = nq/2
     699              : 
     700         2100 :  b1 = two_pi * gprimd(:,1); b2 = two_pi * gprimd(:,2); b3 = two_pi * gprimd(:,3)
     701         2100 :  b1b1 = dot_product(b1, b1); b2b2 = dot_product(b2, b2); b3b3 = dot_product(b3, b3)
     702          210 :  bb(1) = b1b1; bb(2) = b2b2; bb(3) = b3b3
     703              :  b1b2 = dot_product(b1, b2); b2b3 = dot_product(b2, b3); b3b1 = dot_product(b3, b1)
     704              : 
     705          210 :  nprocs = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     706              : 
     707              :  ! In order to speed up the calculation, precompute the sines
     708        10710 :  do iq=1,nq
     709        10500 :    qq=DBLE(iq)*invnq-half
     710        42210 :    bb4sinpiqq_2(:,iq)=bb(:)*four*SIN(pi*qq)**2 ; sin2piqq(iq)=SIN(two_pi*qq)
     711              :  end do
     712              : 
     713        10710 :  do iqx1=1,nq
     714        10500 :    if (modulo(iqx1, nprocs) /= my_rank) cycle ! MPI parallelism
     715         9300 :    qq1(1)=DBLE(iqx1)*invnq-half
     716              :    ! Here take advantage of the q <=> -q symmetry:
     717              :    ! arrange the sampling of qx, qy space to avoid duplicating calculations. Need weights to do this ...
     718              :    !do iqy1=1,nq
     719         9300 :    miniqy1 = nqhalf + 1; maxiqy1 = nq
     720         9300 :    if (iqx1 >= nqhalf) miniqy1 = nqhalf
     721         9300 :    if (iqx1 > nqhalf .and. iqx1 < nq) maxiqy1 = nq - 1
     722              : 
     723       242382 :    do iqy1=miniqy1,maxiqy1
     724       232872 :      qq1(2) = DBLE(iqy1)*invnq - half
     725              :      ! By default, the factor of two is for the q <=> -q symmetry
     726       232872 :      weightq = invnq3*two
     727              :      ! But not all qx qy lines have a symmetric one ...
     728       232872 :      if( (iqx1 == nqhalf .or. iqx1 == nq) .and. (iqy1 == nqhalf .or. iqy1 == nq)) weightq = weightq*half
     729              : 
     730     11886972 :      do iqz1=1,nq
     731     11643600 :        qq1(3) = DBLE(iqz1)*invnq - half
     732              : 
     733              :        ! Refine the mesh for the point close to the origin
     734     11876472 :        if( abs(iqx1-nqhalf) <= nref .and. abs(iqy1-nqhalf) <= nref .and. abs(iqz1-nqhalf) <= nref ) then
     735              :          ! Note that the set of point is symmetric around the central point, while weights are taken into account
     736      1692600 :          do iq=0,nq
     737      6640200 :            qq2(:) = qq1(:)+ (DBLE(iq)*invnq-half)*invnq
     738     11652900 :            bb4sinpiqq2_2(:,iq) =bb(:)*four*SIN(pi*qq2(:))**2; sin2piqq2(:,iq)=SIN(two_pi*qq2(:))
     739              :          end do
     740      1692600 :          do iqx2=0,nq
     741      1660050 :            qq2(1)=qq1(1) + (DBLE(iqx2)*invnq-half ) *invnq
     742     86355150 :            do iqy2=0,nq
     743     84662550 :              qq2(2)=qq1(2) + (DBLE(iqy2)*invnq-half ) *invnq
     744     84662550 :              weightxy=invnq3*weightq
     745     84662550 :              if (iqx2 == 0 .or. iqx2 == nq) weightxy = weightxy*half
     746     84662550 :              if (iqy2 == 0 .or. iqy2 == nq) weightxy = weightxy*half
     747   4404112650 :              do iqz2=0,nq
     748   4317790050 :                qq2(3) = qq1(3) + (DBLE(iqz2)*invnq - half) * invnq
     749   4317790050 :                weightxyz = weightxy
     750   4317790050 :                if (iqz2 == 0 .or. iqz2 == nq) weightxyz = weightxy*half
     751              :                !
     752              :                ! Treat the remaining divergence in the origin as if it would be a spherical integration of 1/q^2
     753              :                if (iqx1/=nqhalf .or. iqy1/=nqhalf .or. iqz1/=nqhalf .or. &
     754   4402452600 :                    iqx2/=nqhalf .or. iqy2/=nqhalf .or. iqz2/=nqhalf ) then
     755              :                  !integratefaux=integratefaux+ faux(qq2, rcut, b1, b2, b3) *invnq**6
     756              :                  integratefaux = integratefaux + &
     757              :                    faux_fast(qq2, bb4sinpiqq2_2(1,iqx2), bb4sinpiqq2_2(2,iqy2), bb4sinpiqq2_2(3,iqz2), &
     758   4317789864 :                              sin2piqq2(1,iqx2), sin2piqq2(2,iqy2), sin2piqq2(3,iqz2), rcut, b1, b2, b3) * weightxyz
     759              :                else
     760          186 :                   integratefaux = integratefaux + 7.7955* ((two_pi)**3/ucvol*invnq3*invnq3 )**(-2./3.) *invnq3*invnq3
     761              :                end if
     762              :              end do
     763              :            end do
     764              :          end do
     765              :        else
     766              :         ! integratefaux=integratefaux+faux(qq1, rcut, b1, b2, b3)*invnq**3
     767              :         integratefaux = integratefaux + &
     768              :           faux_fast(qq1, bb4sinpiqq_2(1,iqx1), bb4sinpiqq_2(2,iqy1), bb4sinpiqq_2(3,iqz1), &
     769     11611050 :                     sin2piqq(iqx1), sin2piqq(iqy1), sin2piqq(iqz1), rcut, b1, b2, b3) * weightq
     770              :        end if
     771              :      end do
     772              :    end do
     773              :  end do
     774              : 
     775          210 :  call xmpi_sum(integratefaux, comm, ierr)
     776              : 
     777          210 : end function integratefaux
     778              : !!***
     779              : 
     780         9357 : real(dp) pure function faux(qq, rcut, b1, b2, b3)
     781              : 
     782              : !Arguments ------------------------------------
     783              :  real(dp),intent(in) :: qq(3)
     784              :  real(dp),intent(in) :: rcut
     785              :  real(dp),intent(in) :: b1(3), b2(3), b3(3)
     786              : 
     787              : !Local variables-------------------------------
     788              :  real(dp) :: bb4sinpiqq1_2, bb4sinpiqq2_2, bb4sinpiqq3_2, sin2piqq1, sin2piqq2, sin2piqq3, b1b1,b2b2,b3b3
     789              : ! *************************************************************************
     790              : 
     791        93570 :  b1b1 = dot_product(b1, b1); b2b2 = dot_product(b2, b2); b3b3 = dot_product(b3, b3)
     792              : 
     793         9357 :  bb4sinpiqq1_2 = b1b1 * four * SIN(pi*qq(1))**2
     794         9357 :  bb4sinpiqq2_2 = b2b2 * four * SIN(pi*qq(2))**2
     795         9357 :  bb4sinpiqq3_2 = b3b3 * four * SIN(pi*qq(3))**2
     796         9357 :  sin2piqq1 = SIN(two_pi*qq(1))
     797         9357 :  sin2piqq2 = SIN(two_pi*qq(2))
     798         9357 :  sin2piqq3 = SIN(two_pi*qq(3))
     799              : 
     800         9357 :  faux = faux_fast(qq, bb4sinpiqq1_2, bb4sinpiqq2_2, bb4sinpiqq3_2, sin2piqq1, sin2piqq2, sin2piqq3, rcut, b1, b2, b3)
     801              : 
     802         9357 : end function faux
     803              : 
     804   4329410271 : real(dp) pure function faux_fast(qq, bb4sinpiqq1_2, bb4sinpiqq2_2, bb4sinpiqq3_2, sin2piqq1, sin2piqq2, sin2piqq3, &
     805              :                                  rcut, b1, b2, b3)
     806              : 
     807              : !Arguments ------------------------------------
     808              :  real(dp),intent(in) :: qq(3)
     809              :  real(dp),intent(in) :: bb4sinpiqq1_2, bb4sinpiqq2_2, bb4sinpiqq3_2, sin2piqq1, sin2piqq2, sin2piqq3, rcut
     810              :  real(dp),intent(in) :: b1(3), b2(3), b3(3)
     811              : 
     812              : !Local variables-------------------------------
     813              :  real(dp) :: b1b2,b2b3,b3b1
     814              : ! *************************************************************************
     815              : 
     816  43294102710 :  b1b2 = dot_product(b1, b2); b2b3 = dot_product(b2, b3); b3b1 = dot_product(b3, b1)
     817              : 
     818              :  faux_fast = bb4sinpiqq1_2 + bb4sinpiqq2_2 + bb4sinpiqq3_2 &
     819              :       +two*( b1b2 * sin2piqq1*sin2piqq2 &
     820              :             +b2b3 * sin2piqq2*sin2piqq3 &
     821              :             +b3b1 * sin2piqq3*sin2piqq1 &
     822   4329410271 :            )
     823              : 
     824   4329410271 :  if (rcut > tol6) then
     825     93105424 :    faux_fast = two_pi*two_pi/faux_fast * exp( -0.25d0*rcut**2* sum( ( qq(1)*b1(:)+qq(2)*b2(:)+qq(3)*b3(:) )**2 ) )
     826              :  else
     827   4306133915 :    faux_fast = two_pi*two_pi/faux_fast
     828              :  endif
     829              : 
     830   4329410271 : end function faux_fast
     831              : !!***
     832              : 
     833              : !----------------------------------------------------------------------
     834              : 
     835              : !!****f* m_vcoul/adapt_nmc
     836              : !! NAME
     837              : !! adapt_nmc
     838              : !!
     839              : !! FUNCTION
     840              : !! Empirical law to decrease the Monte Carlo sampling for large |q+G|, for which the accuracy is not an issue
     841              : 
     842         3393 : integer pure function adapt_nmc(nmc_max, qpg2) result(nmc)
     843              : 
     844              : !Arguments ------------------------------------
     845              :  integer,intent(in)  :: nmc_max
     846              :  real(dp),intent(in) :: qpg2
     847              : ! *************************************************************************
     848              : 
     849         3393 :  nmc = NINT( nmc_max / ( 1.0_dp + 1.0_dp * qpg2**6 ) )
     850         3393 :  nmc = MIN(nmc_max, nmc)
     851         3393 :  nmc = MAX(1, nmc)
     852              : 
     853         3393 : end function adapt_nmc
     854              : !!***
     855              : 
     856              : !----------------------------------------------------------------------
     857              : 
     858              : !!****f* m_vcoul/vcoul_plot
     859              : !! NAME
     860              : !! vcoul_plot
     861              : !!
     862              : !! FUNCTION
     863              : !! Plot vccut(q,G) as a function of |q+G|. Calculate also vc in real space.
     864              : !!
     865              : !! INPUTS
     866              : !!
     867              : !! OUTPUT
     868              : !!
     869              : !! SOURCE
     870              : 
     871            0 : subroutine vcoul_plot(Vcp, Qmesh, Gsph, ng, vc, comm)
     872              : 
     873              : !Arguments ------------------------------------
     874              : !scalars
     875              :  class(vcoul_t),intent(in) :: Vcp
     876              :  integer,intent(in) :: ng, comm
     877              :  type(kmesh_t),intent(in) :: Qmesh
     878              :  type(gsphere_t),intent(in) :: Gsph
     879              : !arrays
     880              :  real(dp),intent(in) :: vc(ng,Qmesh%nibz)
     881              : 
     882              : !Local variables-------------------------------
     883              : !scalars
     884              :  integer,parameter :: master = 0
     885              :  integer :: icount,idx_Sm1G,ierr,ig,igs,ii,iq_bz,iq_ibz,iqg,ir,isym,itim
     886              :  integer :: my_start,my_stop,nqbz,nqibz,nr,ntasks,my_rank,unt
     887              :  real(dp) :: arg,fact,l1,l2,l3,lmax,step,tmp,vcft,vc_bare
     888              :  character(len=500) :: msg
     889              :  character(len=fnlen) :: filnam
     890              : !arrays
     891            0 :  integer,allocatable :: insort(:)
     892              :  real(dp) :: b1(3),b2(3),b3(3),gmet(3,3),gprimd(3,3),qbz(3),qpgc(3)
     893            0 :  real(dp),allocatable :: qpg_mod(:),rr(:,:,:),vcr(:,:),vcr_cut(:,:)
     894              : !************************************************************************
     895              : 
     896            0 :  if (trim(Vcp%mode) /= 'CYLINDER') RETURN
     897              : 
     898            0 :  my_rank = xmpi_comm_rank(comm)
     899              : 
     900            0 :  nqibz=Vcp%nqibz; nqbz=Qmesh%nbz
     901            0 :  gmet=Gsph%gmet; gprimd=Gsph%gprimd
     902              : 
     903            0 :  b1(:)=two_pi*gprimd(:,1)
     904            0 :  b2(:)=two_pi*gprimd(:,2)
     905            0 :  b3(:)=two_pi*gprimd(:,3)
     906              : 
     907              :  ! Compare in Fourier space the true Coulomb with the cutted one.
     908            0 :  if (my_rank == master) then
     909            0 :    ABI_MALLOC(insort, (nqibz * ng))
     910            0 :    ABI_MALLOC(qpg_mod, (nqibz * ng))
     911            0 :    iqg = 1
     912            0 :    do iq_ibz=1,nqibz
     913            0 :      do ig=1,ng
     914            0 :        qpg_mod(iqg) = normv(Qmesh%ibz(:,iq_ibz) + Gsph%gvec(:,ig), gmet,'g')
     915            0 :        insort(iqg) = iqg; iqg = iqg + 1
     916              :      end do
     917              :    end do
     918            0 :    call sort_dp(nqibz * ng, qpg_mod, insort, tol14)
     919              : 
     920            0 :    filnam='_VCoulFT_'
     921            0 :    call isfile(filnam, 'new')
     922            0 :    if (open_file(filnam, msg, newunit=unt, status='new', form='formatted') /= 0) then
     923            0 :      ABI_ERROR(msg)
     924              :    end if
     925              :    write(unt,'(a,i3,a,i6,a)')&
     926            0 :     '#   |q+G|       q-point (Tot no.',nqibz,')        Gvec (',ng,')     vc_bare(q,G)    vc_cutoff(q,G) '
     927              : 
     928            0 :    do iqg=1,nqibz*ng
     929            0 :      iq_ibz = (insort(iqg) - 1) / ng + 1
     930            0 :      ig = (insort(iqg)) - (iq_ibz-1) * ng
     931            0 :      vc_bare = zero
     932            0 :      if (qpg_mod(iqg) > tol16) vc_bare = four_pi / qpg_mod(iqg) ** 2
     933              :      write(unt,'(f12.6,2x,3f8.4,2x,3i6,2x,2es14.6)')&
     934            0 :        qpg_mod(iqg), Qmesh%ibz(:,iq_ibz), Gsph%gvec(:,ig), vc_bare, vc(ig, iq_ibz)
     935              :    end do
     936              : 
     937            0 :    close(unt)
     938            0 :    ABI_FREE(insort)
     939            0 :    ABI_FREE(qpg_mod)
     940              :  end if ! my_rank==master
     941              : 
     942              :  ! Fourier transform back to real space just to check cutoff implementation.
     943            0 :  ntasks= nqbz * ng
     944            0 :  call xmpi_split_work(ntasks, comm, my_start, my_stop)
     945              : 
     946            0 :  l1 = NORM2(Vcp%rprimd(:,1))
     947            0 :  l2 = NORM2(Vcp%rprimd(:,2))
     948            0 :  l3 = NORM2(Vcp%rprimd(:,3))
     949              : 
     950            0 :  nr = 50
     951            0 :  lmax=MAX(l1,l2,l3) ; step=lmax/(nr-1)
     952            0 :  fact = one / (Vcp%ucvol * nqbz)
     953              : 
     954              :  ! numb coding
     955            0 :  ABI_CALLOC(rr, (3, nr, 3))
     956            0 :  do ir=1,nr
     957            0 :    rr(1:3,ir,1:3)=(ir-1)*step
     958              :  end do
     959              : 
     960            0 :  ABI_CALLOC(vcr, (nr, 3))
     961            0 :  ABI_CALLOC(vcr_cut, (nr, 3))
     962              : 
     963            0 :  do iq_bz=1,nqbz
     964            0 :    call Qmesh%get_BZ_item(iq_bz, qbz, iq_ibz, isym, itim)
     965            0 :    if (ABS(qbz(1))<0.01) qbz(1)=zero
     966            0 :    if (ABS(qbz(2))<0.01) qbz(2)=zero
     967            0 :    if (ABS(qbz(3))<0.01) qbz(3)=zero
     968            0 :    igs=1; if (ALL(qbz(:)==zero)) igs=2
     969            0 :    do ig=igs,ng
     970            0 :      icount=ig+(iq_bz-1)*ng
     971            0 :      if (icount < my_start .or. icount > my_stop) CYCLE
     972            0 :      idx_Sm1G = Gsph%rottbm1(ig,itim,isym) ! IS{^-1}G
     973            0 :      vcft=vc(idx_Sm1G,iq_ibz)
     974            0 :      qpgc(:)=qbz(:)+Gsph%gvec(:,ig) ; qpgc(:)=b1(:)*qpgc(1)+b2(:)*qpgc(2)+b3(:)*qpgc(3)
     975            0 :      tmp=NORM2(qpgc) ; tmp=tmp**2
     976            0 :      do ii=1,3
     977            0 :        do ir=1,nr
     978            0 :          arg=DOT_PRODUCT(rr(:,ir,ii),qpgc)
     979            0 :          vcr_cut(ir,ii)=vcr_cut(ir,ii) + vcft*COS(arg)
     980            0 :          vcr    (ir,ii)=vcr    (ir,ii) + four_pi/tmp*COS(arg)
     981              :        end do
     982              :      end do
     983              :    end do !ig
     984              :  end do !iq_ibz
     985              : 
     986            0 :  call xmpi_sum_master(vcr_cut,master,comm,ierr)
     987            0 :  call xmpi_sum_master(vcr    ,master,comm,ierr)
     988              : 
     989            0 :  if (my_rank == master) then
     990            0 :    filnam='_VCoulR_'
     991            0 :    call isfile(filnam, 'new')
     992            0 :    if (open_file(filnam,msg,newunit=unt,status='new',form='formatted') /= 0) then
     993            0 :      ABI_ERROR(msg)
     994              :    end if
     995            0 :    write(unt,'(a)')'# length  vc_bare(r)   vc_cut(r) '
     996            0 :    do ir=1,nr
     997            0 :      write(unt,'(7es18.6)')(ir-1)*step,(fact*vcr(ir,ii),fact*vcr_cut(ir,ii),ii=1,3)
     998              :    end do
     999            0 :    close(unt)
    1000              :  end if
    1001              : 
    1002            0 :  ABI_FREE(rr)
    1003            0 :  ABI_FREE(vcr)
    1004            0 :  ABI_FREE(vcr_cut)
    1005              : 
    1006            0 : end subroutine vcoul_plot
    1007              : !!***
    1008              : 
    1009              : !----------------------------------------------------------------------
    1010              : 
    1011              : !!****f* m_vcoul/vcoul_print
    1012              : !! NAME
    1013              : !! vcoul_print
    1014              : !!
    1015              : !! FUNCTION
    1016              : !!  Print info on a Coulomb datatype.
    1017              : !!
    1018              : !! INPUTS
    1019              : !!  units=Unit numbers for output
    1020              : !!  [prtvol]=Verbosity level
    1021              : !!
    1022              : !! SOURCE
    1023              : 
    1024          407 : subroutine vcoul_print(Vcp, units, prtvol)
    1025              : 
    1026              : !Arguments ------------------------------------
    1027              : !scalars
    1028              :  class(vcoul_t),intent(in) :: Vcp
    1029              :  integer,intent(in) :: units(:)
    1030              :  integer,intent(in),optional :: prtvol
    1031              : 
    1032              : !Local variables-------------------------------
    1033              : !scalars
    1034              :  integer :: ii, my_prtvol, iqlwl
    1035              :  character(len=500) :: msg
    1036              : ! *************************************************************************
    1037              : 
    1038          407 :  my_prtvol=0; if (PRESENT(prtvol)) my_prtvol=prtvol
    1039              : 
    1040          408 :  select case (Vcp%mode)
    1041              : 
    1042              :  case ('MINIBZ')
    1043            1 :    write(msg,'(3a)')ch10,' vcoul_init : cutoff-mode = ',trim(Vcp%mode)
    1044            1 :    call wrtout(units, msg)
    1045              : 
    1046              :  case ('MINIBZ-ERF')
    1047            1 :    write(msg,'(3a)')ch10,' vcoul_init : cutoff-mode = ',trim(Vcp%mode)
    1048            1 :    call wrtout(units, msg)
    1049            1 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    1050            1 :      ' === Error function cutoff === ',ch10,ch10,&
    1051            2 :      '  Cutoff radius ......... ',Vcp%rcut,' [Bohr] ',ch10
    1052            1 :    call wrtout(units, msg)
    1053              : 
    1054              :  case ('MINIBZ-ERFC')
    1055            1 :    write(msg,'(3a)')ch10,' vcoul_init : cutoff-mode = ',trim(Vcp%mode)
    1056            1 :    call wrtout(units, msg)
    1057            1 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    1058            1 :      ' === Complement Error function cutoff === ',ch10,ch10,&
    1059            2 :      '  Cutoff radius ......... ',Vcp%rcut,' [Bohr] ',ch10
    1060            1 :    call wrtout(units, msg)
    1061              : 
    1062              :  case ('SPHERE')
    1063           46 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    1064           46 :     ' === Spherical cutoff === ',ch10,ch10,&
    1065           46 :     '  Cutoff radius ......... ',Vcp%rcut,' [Bohr] ',ch10,&
    1066           92 :     '  Volume of the sphere .. ',four_pi/three*Vcp%rcut**3,' [Bohr^3] '
    1067              :     !FB: This has no meaning here! &  '  Sphere centered at .... ',Vcp%boxcenter,' (r.l.u) ',ch10
    1068              :     !MG It might be useful if the system is not centered on the origin because in this case the
    1069              :     !   matrix elements of the Coulomb have to be multiplied by a phase depending on boxcenter.
    1070              :     !   I still have to decide if it is useful to code this possibility and which variable use to
    1071              :     !   define the center (boxcenter is used in the tddft part).
    1072           46 :    call wrtout(units, msg)
    1073              : 
    1074              :  case ('CYLINDER')
    1075            8 :    ii=imin_loc(ABS(Vcp%pdir-1))
    1076            2 :    write(msg,'(5a,f10.4,3a,i2,2a,3f10.2,a)')ch10,&
    1077            2 :      ' === Cylindrical cutoff === ',ch10,ch10,&
    1078            2 :      '  Cutoff radius ............... ',Vcp%rcut,' [Bohr] ',ch10,&
    1079            2 :      '  Axis parallel to direction... ',ii,ch10,&
    1080            4 :      '  Passing through point ....... ',Vcp%boxcenter,' (r.l.u) '
    1081            2 :    call wrtout(units, msg)
    1082              : 
    1083            2 :    write(msg,'(2a)')'  Infinite length  ....... ',ch10
    1084            2 :    if (Vcp%hcyl/=zero) write(msg,'(a,f8.5,2a)')'  Finite length of ....... ',Vcp%hcyl,' [Bohr] ',ch10
    1085            2 :    call wrtout(units, msg)
    1086              : 
    1087              :  CASE ('SLAB')
    1088            0 :    write(msg,'(5a,f10.4,3a,3f10.2,2a)')ch10,&
    1089            0 :      ' === Surface cutoff === ',ch10,ch10,&
    1090            0 :      '  Cutoff radius .................... ',Vcp%rcut,' [Bohr] ',ch10,&
    1091            0 :      '  Central plane passing through .... ',Vcp%boxcenter,' (r.l.u) ',ch10
    1092            0 :    call wrtout(units, msg)
    1093              :    !write(msg,'(a)')'  Infinite length  .......'
    1094              :    !if (Vcp%hcyl/=zero) write(msg,'(a,f8.5,a)')'  Finite length of .......',Vcp%hcyl,' [Bohr] '
    1095              :    !call wrtout(units, msg)
    1096              : 
    1097              :  case ('AUXILIARY_FUNCTION')
    1098          212 :    write(msg,'(3a)')ch10,' vcoul_init : cutoff-mode = ',trim(Vcp%mode)
    1099          212 :    call wrtout(units, msg)
    1100              : 
    1101              :  case ('AUX_GB')
    1102            8 :    write(msg,'(3a)')ch10,' vcoul_init : cutoff-mode = ',trim(Vcp%mode)
    1103            8 :    call wrtout(units, msg)
    1104              : 
    1105              :  case ('CRYSTAL')
    1106          117 :    write(msg,'(3a)')ch10,' vcoul_init : cutoff-mode = ',trim(Vcp%mode)
    1107          117 :    call wrtout(units, msg)
    1108              : 
    1109              :  case ('ERF')
    1110            1 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    1111            1 :      ' === Error function cutoff === ',ch10,ch10,&
    1112            2 :      '  Cutoff radius ......... ',Vcp%rcut,' [Bohr] ',ch10
    1113            1 :    call wrtout(units, msg)
    1114              : 
    1115              :  case ('ERFC')
    1116           18 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    1117           18 :      ' === Complement Error function cutoff === ',ch10,ch10,&
    1118           36 :      '  Cutoff radius ......... ',Vcp%rcut,' [Bohr] ',ch10
    1119           18 :    call wrtout(units, msg)
    1120              : 
    1121              :  case default
    1122          407 :    ABI_BUG(sjoin('Unknown cutoff mode: ', Vcp%mode))
    1123              :  end select
    1124              : 
    1125          407 :  if (Vcp%nqlwl > 0) then
    1126          407 :    write(msg,'(a,i3)')" q-points for optical limit: ",Vcp%nqlwl
    1127          407 :    call wrtout(units, msg)
    1128          814 :    do iqlwl=1,Vcp%nqlwl
    1129          407 :      write(msg,'(1x,i5,a,2x,3f12.6)') iqlwl,')',Vcp%qlwl(:,iqlwl)
    1130          814 :      call wrtout(units, msg)
    1131              :    end do
    1132              :  end if
    1133              : 
    1134          407 : end subroutine vcoul_print
    1135              : !!***
    1136              : 
    1137              : !----------------------------------------------------------------------
    1138              : 
    1139              : !!****f* m_vcoul/vcoul_free
    1140              : !! NAME
    1141              : !! vcoul_free
    1142              : !!
    1143              : !! FUNCTION
    1144              : !!  Free dynamic memory
    1145              : !!
    1146              : !! SOURCE
    1147              : 
    1148          404 : subroutine vcoul_free(Vcp)
    1149              : 
    1150              : !Arguments ------------------------------------
    1151              :  class(vcoul_t),intent(inout) :: Vcp
    1152              : ! *************************************************************************
    1153              : 
    1154          404 :  ABI_SFREE(Vcp%qibz)
    1155          404 :  ABI_SFREE(Vcp%qlwl)
    1156          404 :  ABI_SFREE(Vcp%vc_sqrt)
    1157          404 :  ABI_SFREE(Vcp%vc_sqrt_resid)
    1158          404 :  ABI_SFREE(Vcp%vcqlwl_sqrt)
    1159              : 
    1160          404 : end subroutine vcoul_free
    1161              : !!***
    1162              : 
    1163              : !----------------------------------------------------------------------
    1164              : 
    1165              : !!****f* m_vcoul/mc_init
    1166              : !! NAME
    1167              : !! mc_init
    1168              : !!
    1169              : !! FUNCTION
    1170              : !!
    1171              : !! SOURCE
    1172              : 
    1173            3 : subroutine mc_init(mc, rprimd, ucvol, gprimd, gmet, kptrlatt)
    1174              : 
    1175              : !Arguments ------------------------------------
    1176              :  class(mc_t),intent(out) :: mc
    1177              :  real(dp),intent(in) :: rprimd(3,3), ucvol, gprimd(3,3), gmet(3,3)
    1178              :  integer,intent(in) :: kptrlatt(3,3)
    1179              : 
    1180              : !Local variables-------------------------------
    1181              :  integer,parameter :: ncell=3
    1182              :  integer :: nseed, i1,i2,i3,imc
    1183              :  real(dp) :: lmin,vlength, ucvol_sc
    1184              :  real(dp) :: rprimd_sc(3,3),gprimd_sc(3,3),gmet_sc(3,3),rmet_sc(3,3), qcart2red(3,3), qtmp(3),qmin(3),qmin_cart(3)
    1185            3 :  integer, allocatable :: seed(:)
    1186              : ! *************************************************************************
    1187              : 
    1188           39 :  mc%gmet = gmet; mc%ucvol = ucvol
    1189              : 
    1190              :  ! Supercell defined by the k-mesh
    1191          156 :  rprimd_sc(:,:) = MATMUL(rprimd, kptrlatt)
    1192            3 :  call metric(gmet_sc, gprimd_sc, -1, rmet_sc, rprimd_sc, ucvol_sc)
    1193              : 
    1194           39 :  qcart2red(:,:) = two_pi * gprimd(:,:)
    1195            3 :  call matrginv(qcart2red, 3, 3)
    1196              : 
    1197              :  ! Find the largest sphere inside the miniBZ in order to integrate the divergence analytically
    1198            3 :  mc%q0sph = HUGE(one)
    1199           21 :  do i1 = -ncell+1, ncell
    1200           18 :    qtmp(1) = dble(i1) * 0.5_dp
    1201          129 :    do i2 = -ncell+1, ncell
    1202          108 :      qtmp(2) = dble(i2) * 0.5_dp
    1203          774 :      do i3 = -ncell+1, ncell
    1204          648 :        qtmp(3) = dble(i3) * 0.5_dp
    1205          648 :        if (i1 == 0 .AND. i2 == 0 .AND. i3 == 0) cycle
    1206          645 :        vlength = normv(qtmp, gmet_sc, 'G')
    1207          753 :        if (vlength < mc%q0sph) mc%q0sph = vlength
    1208              :      enddo
    1209              :    enddo
    1210              :  enddo
    1211              : 
    1212              :  ! Setup the random vectors for the Monte Carlo sampling of the miniBZ at q = 0
    1213            3 :  mc%nmc_max = 2500000
    1214            3 :  ABI_MALLOC(mc%qran,(3, mc%nmc_max))
    1215            3 :  call random_seed(size=nseed)
    1216            9 :  ABI_MALLOC(seed, (nseed))
    1217           27 :  do i1=1,nseed
    1218           27 :    seed(i1) = NINT(SQRT(DBLE(i1) * 103731))
    1219              :  end do
    1220            3 :  call random_seed(put=seed)
    1221            3 :  call random_number(mc%qran)
    1222            3 :  ABI_FREE(seed)
    1223              : 
    1224              :  ! Overide the first "random vector" with 0
    1225           12 :  mc%qran(:,1) = zero
    1226              : 
    1227              :  ! Fold qran into the Wignez-Seitz cell around q = 0
    1228      7500000 :  do imc=2,mc%nmc_max
    1229              :    lmin = HUGE(one)
    1230     52499979 :    do i1 = -ncell+1, ncell
    1231     44999982 :      qtmp(1) = mc%qran(1,imc) + dble(i1)
    1232    322499871 :      do i2 = -ncell+1, ncell
    1233    269999892 :        qtmp(2) = mc%qran(2,imc) + dble(i2)
    1234   1934999226 :        do i3 = -ncell+1, ncell
    1235   1619999352 :          qtmp(3) = mc%qran(3,imc) + dble(i3)
    1236   1619999352 :          vlength = normv(qtmp, gmet_sc, 'G')
    1237   1889999244 :          if (vlength < lmin) then
    1238     42272448 :            lmin = vlength
    1239              :            ! Get the q-vector in cartesian coordinates
    1240    676359168 :            qmin_cart(:) = two_pi * MATMUL( gprimd_sc(:,:) , qtmp )
    1241              :            ! Transform it back to the reciprocal space
    1242    549541824 :            qmin(:) = MATMUL(qcart2red , qmin_cart)
    1243              :          end if
    1244              :        enddo
    1245              :      enddo
    1246              :    enddo
    1247              : 
    1248     29999991 :    mc%qran(:,imc) = qmin(:)
    1249              :  enddo
    1250              : 
    1251            3 : end subroutine mc_init
    1252              : !!***
    1253              : 
    1254              : !----------------------------------------------------------------------
    1255              : 
    1256              : !!****f* m_vcoul/mc_integrate
    1257              : !! NAME
    1258              : !! mc_integrate
    1259              : !!
    1260              : !! FUNCTION
    1261              : !!
    1262              : !! SOURCE
    1263              : 
    1264           12 : subroutine mc_integrate(mc, mode, qibz, ng, gvec, rcut2, nkbz, vcoul, comm)
    1265              : 
    1266              : !Arguments ------------------------------------
    1267              :  class(mc_t),intent(in) :: mc
    1268              :  real(dp),intent(in) :: rcut2
    1269              :  integer,intent(in) :: nkbz, ng, comm
    1270              :  character(len=*),intent(in) :: mode
    1271              :  real(dp),intent(in) :: qibz(3)
    1272              :  integer,intent(in) :: gvec(3, ng)
    1273              :  real(dp),intent(out) :: vcoul(ng)
    1274              : 
    1275              : !Local variables-------------------------------
    1276              :  integer,parameter :: master = 0
    1277              :  integer :: ig, ig0, imc, nmc, my_rank, nprocs, ierr
    1278              :  logical :: q_is_gamma
    1279              :  real(dp)  :: qpg2, qpg(3)
    1280              : ! *************************************************************************
    1281              : 
    1282           12 :  my_rank = xmpi_comm_rank(comm); nprocs = xmpi_comm_size(comm)
    1283           21 :  q_is_gamma = all(abs(qibz) < tol16)
    1284              : 
    1285              :  ! Find index of G=0 in gvec.
    1286           12 :  ig0 = -1
    1287           12 :  do ig=1,ng
    1288           48 :    if (all(gvec(:, ig) == 0)) then
    1289              :      ig0 = ig; exit
    1290              :    end if
    1291              :  end do
    1292           12 :  ABI_CHECK(ig0 /= -1, "Cannot find G=0 in gvec!")
    1293              : 
    1294         3408 :  vcoul = zero
    1295              : 
    1296           12 :  select case (trim(mode))
    1297              : 
    1298              :  case ('MINIBZ')
    1299         1136 :    do ig=1,ng
    1300         1132 :      if (mod(ig, nprocs) /= my_rank) cycle ! MPI parallelism.
    1301         1132 :      if (q_is_gamma .and. ig == ig0) cycle
    1302         4524 :      qpg(:) = qibz(:) + gvec(:,ig)
    1303         1131 :      qpg2 = normv(qpg, mc%gmet, 'G')**2
    1304         1131 :      nmc = adapt_nmc(mc%nmc_max, qpg2)
    1305     43850951 :      do imc=1,nmc
    1306    175399264 :        qpg(:) = qibz(:) + gvec(:,ig) + mc%qran(:,imc)
    1307     43849816 :        qpg2 = normv(qpg, mc%gmet, 'G') ** 2
    1308     43850948 :        vcoul(ig) = vcoul(ig) + four_pi / qpg2 / REAL(nmc, dp)
    1309              :      end do
    1310              :    end do ! ig
    1311              : 
    1312            4 :    if (q_is_gamma .and. my_rank == master) then
    1313              :      ! Compute ig0 component
    1314            1 :      vcoul(ig0) = four_pi**2 * nkbz * mc%ucvol / ( 8.0_dp * pi**3 ) * mc%q0sph
    1315      2500001 :      do imc=1,mc%nmc_max
    1316     10000000 :        qpg(:) = qibz(:) + gvec(:,ig0) + mc%qran(:,imc)
    1317      2500000 :        qpg2 = normv(qpg, mc%gmet, 'G')**2
    1318      2500001 :        if (qpg2 > mc%q0sph ** 2) vcoul(ig0) = vcoul(ig0) + four_pi / qpg2 / REAL(mc%nmc_max, dp)
    1319              :      end do
    1320              :    end if
    1321              : 
    1322              :  case ('MINIBZ-ERFC')
    1323         1136 :    do ig=1,ng
    1324         1132 :      if (mod(ig, nprocs) /= my_rank) cycle ! MPI parallelism.
    1325         1132 :      if (q_is_gamma .and. ig == ig0) cycle
    1326         4524 :      qpg(:) = qibz(:) + gvec(:,ig)
    1327         1131 :      qpg2 = normv(qpg, mc%gmet, 'G')**2
    1328         1131 :      nmc = adapt_nmc(mc%nmc_max, qpg2)
    1329     43850951 :      do imc=1,nmc
    1330    175399264 :        qpg(:) = qibz(:) + gvec(:,ig) + mc%qran(:,imc)
    1331     43849816 :        qpg2 = normv(qpg, mc%gmet, 'G')**2
    1332     43850948 :        vcoul(ig) = vcoul(ig) + four_pi / qpg2 / REAL(nmc,dp) * (  one - EXP( -0.25d0 * rcut2 * qpg2 ) )
    1333              :      end do
    1334              :    end do ! ig
    1335              : 
    1336            4 :    if (q_is_gamma .and. my_rank == master) then
    1337              :      ! Override ig0 component
    1338              :      vcoul(ig0) = four_pi**2 * nkbz * mc%ucvol / ( 8.0_dp * pi**3 ) &
    1339            1 :         * ( mc%q0sph - SQRT(pi/rcut2) * abi_derf(0.5_dp*SQRT(rcut2)*mc%q0sph) )
    1340      2500001 :      do imc=1,mc%nmc_max
    1341     10000000 :        qpg(:) = qibz(:) + gvec(:,ig0) + mc%qran(:,imc)
    1342      2500000 :        qpg2 = normv(qpg, mc%gmet, 'G')**2
    1343      2500001 :        if (qpg2 > mc%q0sph**2) then
    1344       800113 :          vcoul(ig0) = vcoul(ig0) + four_pi / qpg2 / REAL(mc%nmc_max,dp) * (one - EXP( -0.25d0 * rcut2 * qpg2))
    1345              :        end if
    1346              :      end do
    1347              :    end if
    1348              : 
    1349              :  case ('MINIBZ-ERF')
    1350         1136 :    do ig=1,ng
    1351         1132 :      if (mod(ig, nprocs) /= my_rank) cycle ! MPI parallelism.
    1352         1132 :      if (q_is_gamma .and. ig == ig0) cycle
    1353         4524 :      qpg(:) = qibz(:) + gvec(:,ig)
    1354         1131 :      qpg2 = normv(qpg, mc%gmet, 'G')**2
    1355         1131 :      nmc = adapt_nmc(mc%nmc_max, qpg2)
    1356     43850951 :      do imc=1,nmc
    1357    175399264 :        qpg(:) = qibz(:) + gvec(:,ig) + mc%qran(:,imc)
    1358     43849816 :        qpg2 = normv(qpg, mc%gmet, 'G')**2
    1359     43850948 :        vcoul(ig) = vcoul(ig) + four_pi / qpg2 / REAL(nmc,dp) * EXP( -0.25d0 * rcut2 * qpg2 )
    1360              :      end do
    1361              :    end do ! ig
    1362              : 
    1363            4 :    if (q_is_gamma .and. my_rank == master) then
    1364              :      ! Override ig=ig0 component
    1365            1 :      vcoul(ig0) = four_pi**2 * nkbz * mc%ucvol / ( 8.0_dp * pi**3 ) * SQRT(pi/rcut2) * abi_derf(0.5_dp*SQRT(rcut2)*mc%q0sph)
    1366              : 
    1367      2500001 :      do imc=1,mc%nmc_max
    1368     10000000 :        qpg(:) = qibz(:) + gvec(:,ig0) + mc%qran(:,imc)
    1369      2500000 :        qpg2 = normv(qpg, mc%gmet, 'G')**2
    1370      2500001 :        if (qpg2 > mc%q0sph**2) then
    1371       800113 :          vcoul(ig0) = vcoul(ig0) + four_pi / qpg2 / REAL(mc%nmc_max,dp) *  EXP( -0.25d0 * rcut2 * qpg2 )
    1372              :        end if
    1373              :      end do
    1374              :    end if
    1375              : 
    1376              :  case default
    1377           12 :    ABI_ERROR(sjoin("Invalid mode:", mode))
    1378              :  end select
    1379              : 
    1380              :  ! Collect result on each MPI proc.
    1381           12 :  call xmpi_sum(vcoul, comm, ierr)
    1382              : 
    1383           12 : end subroutine mc_integrate
    1384              : !!***
    1385              : 
    1386              : !----------------------------------------------------------------------
    1387              : 
    1388              : !!****f* m_vcoul/mc_free
    1389              : !! NAME
    1390              : !! mc_free
    1391              : !!
    1392              : !! FUNCTION
    1393              : !!  Free dynamic memory
    1394              : !!
    1395              : !! SOURCE
    1396              : 
    1397            3 : subroutine mc_free(mc)
    1398              : 
    1399              : !Arguments ------------------------------------
    1400              :  class(mc_t),intent(inout) :: mc
    1401              : ! *************************************************************************
    1402              : 
    1403            3 :  ABI_SFREE(mc%qran)
    1404              : 
    1405            3 : end subroutine mc_free
    1406              : !!***
    1407              : 
    1408              : !----------------------------------------------------------------------
    1409              : 
    1410              : !!****f* m_vcoul/beigi_cylinder_limit
    1411              : !! NAME
    1412              : !! beigi_cylinder_limit
    1413              : !!
    1414              : !! FUNCTION
    1415              : !!
    1416              : !! SOURCE
    1417              : 
    1418            1 : subroutine beigi_cylinder_limit(opt_cylinder, cryst, nqibz, nkbz, rcut, hcyl, boxcenter, pdir, i_sz)
    1419              : 
    1420              : !Arguments ------------------------------------
    1421              :  integer,intent(in) :: opt_cylinder, nqibz, nkbz, pdir(3)
    1422              :  type(crystal_t),intent(in) :: cryst
    1423              :  real(dp),intent(in) :: rcut, hcyl, boxcenter(3)
    1424              :  real(dp),intent(out) :: i_sz
    1425              : 
    1426              : !Local variables-------------------------------
    1427              :  integer :: ii, iq, npar, npt, gamma_pt(3,1)
    1428              :  real(dp) :: step, bz_plane, dx, integ, q0_vol, q0_volsph, b1(3),b2(3),b3(3)
    1429            1 :  real(dp),allocatable :: cov(:,:),par(:),qfit(:,:),sigma(:),var(:), vcfit(:,:),xx(:),yy(:)
    1430              : ! *************************************************************************
    1431              : 
    1432            7 :  b1 = two_pi * cryst%gprimd(:,1); b2 = two_pi * cryst%gprimd(:,2); b3 = two_pi * cryst%gprimd(:,3)
    1433              : 
    1434            1 :  npt =100
    1435            1 :  npar=8; gamma_pt = RESHAPE(([0, 0, 0]), [3, 1])
    1436            1 :  ABI_MALLOC(qfit, (3, npt))
    1437            1 :  ABI_MALLOC(vcfit, (1, npt))
    1438            1 :  if (nqibz == 1) then
    1439            0 :    ABI_ERROR("nqibz == 1 not supported when Beigi's method is used")
    1440              :  endif
    1441          401 :  qfit(:,:)=zero
    1442          101 :  step=half/(npt * (nqibz-1))              ; qfit(3,:)=arth(tol6,step,npt)
    1443              :  !step=(half/(nqibz-1)/tol6)**(one/npt) ; qfit(3,:)=geop(tol6,step,npt)
    1444              : 
    1445          101 :  do iq=1,npt
    1446              :    call cutoff_cylinder(qfit(:,iq),1,gamma_pt,rcut,hcyl,pdir,boxcenter,&
    1447          101 :                         Cryst%rprimd,vcfit(:,iq),opt_cylinder, xmpi_comm_self)
    1448              :  end do
    1449              : 
    1450            1 :  ABI_MALLOC(xx, (npt))
    1451            1 :  ABI_MALLOC(yy, (npt))
    1452            1 :  ABI_MALLOC(sigma, (npt))
    1453            1 :  ABI_MALLOC(par, (npar))
    1454            1 :  ABI_MALLOC(var, (npar))
    1455            1 :  ABI_MALLOC(cov, (npar, npar))
    1456              : 
    1457          101 :  do ii=1,npt
    1458          101 :    xx(ii) = normv(qfit(:,ii), cryst%gmet, 'G')
    1459              :  end do
    1460            1 :  ABI_FREE(qfit)
    1461          201 :  sigma=one ; yy(:)=vcfit(1,:)
    1462            1 :  ABI_FREE(vcfit)
    1463              :  !call llsfit_svd(xx,yy,sigma,npar,K0fit,chisq,par,var,cov,info)
    1464              :  !do ii=1,npt
    1465              :  ! write(99,*)xx(ii),yy(ii),DOT_PRODUCT(par,K0fit(xx(ii),npar))
    1466              :  !end do
    1467            1 :  bz_plane=l2norm(b1.x.b2)
    1468              :  !integ=K0fit_int(xx(npt),par,npar)
    1469              :  !write(std_out,*)' SVD fit : chi-square',chisq
    1470              :  !write(std_out,*)' fit-parameters : ',par
    1471              :  !write(std_out,*)' variance ',var
    1472              :  !write(std_out,*)' bz_plane ',bz_plane
    1473              :  !write(std_out,*)' SCD integ ',integ
    1474              :  ! Here Im assuming homogeneous mesh
    1475            1 :  dx=(xx(2)-xx(1))
    1476            1 :  integ=yy(2)*dx*3.0/2.0
    1477           97 :  integ=integ+SUM(yy(3:npt-2))*dx
    1478            1 :  integ=integ+yy(npt-1)*dx*3.0/2.0
    1479              :  !write(std_out,*)' simple integral',integ
    1480            1 :  q0_volsph = (two_pi)**3 / (nkbz * cryst%ucvol)
    1481            1 :  q0_vol=bz_plane*two*xx(npt)
    1482              :  !write(std_out,*)' q0 sphere : ',q0_volsph,' q0_vol cyl ',q0_vol
    1483            1 :  i_sz = bz_plane * two * integ / q0_vol
    1484              :  !write(std_out,*)' spherical approximation ',four_pi*7.44*q0_volsph**(-two_thirds)
    1485              :  !write(std_out,*)' Cylindrical cutoff value ',i_sz
    1486              :  !i_sz=four_pi*7.44*q0_vol**(-two_thirds)
    1487              : 
    1488            1 :  ABI_FREE(xx)
    1489            1 :  ABI_FREE(yy)
    1490            1 :  ABI_FREE(sigma)
    1491            1 :  ABI_FREE(par)
    1492            1 :  ABI_FREE(var)
    1493            1 :  ABI_FREE(cov)
    1494              : 
    1495            1 : end subroutine beigi_cylinder_limit
    1496              : !!***
    1497              : 
    1498              : !----------------------------------------------------------------------
    1499              : 
    1500              : !!****f* m_vcoul/beigi_surface_limit
    1501              : !! NAME
    1502              : !! beigi_surface_limit
    1503              : !!
    1504              : !! FUNCTION
    1505              : !!
    1506              : !! SOURCE
    1507              : 
    1508            0 : subroutine beigi_surface_limit(opt_slab, cryst, nqibz, nkbz, rcut, alpha, boxcenter, pdir, i_sz)
    1509              : 
    1510              : !Arguments ------------------------------------
    1511              :  integer,intent(in) :: opt_slab, nqibz, nkbz, pdir(3)
    1512              :  type(crystal_t),intent(in) :: cryst
    1513              :  real(dp),intent(in) :: rcut, alpha(3), boxcenter(3)
    1514              :  real(dp),intent(out) :: i_sz
    1515              : 
    1516              : !Local variables-------------------------------
    1517              :  integer :: ii, npt, gamma_pt(3,1)
    1518              :  real(dp) :: step, bz_plane, dx, integ, q0_vol, q0_volsph, b1(3),b2(3),b3(3)
    1519            0 :  real(dp),allocatable :: qfit(:,:),sigma(:),vcfit(:,:),xx(:),yy(:), qcart(:,:)
    1520              : ! *************************************************************************
    1521              : 
    1522            0 :  b1 = two_pi * cryst%gprimd(:,1); b2 = two_pi * cryst%gprimd(:,2); b3 = two_pi * cryst%gprimd(:,3)
    1523              : 
    1524            0 :  gamma_pt=RESHAPE([0, 0, 0], [3, 1]) ! Gamma point
    1525            0 :  npt=100 ! Number of points in 1D
    1526            0 :  ABI_MALLOC(qfit, (3, npt))
    1527            0 :  ABI_MALLOC(qcart, (3, npt))
    1528            0 :  ABI_MALLOC(vcfit, (1, npt))
    1529            0 :  if (nqibz == 1) then
    1530            0 :    ABI_ERROR("nqibz == 1 not supported when Beigi's method is used")
    1531              :  endif
    1532            0 :  qfit(:,:)=zero
    1533            0 :  qcart(:,:)=zero
    1534              :  ! Size of the third vector
    1535            0 :  bz_plane=l2norm(b3)
    1536            0 :  q0_volsph=(two_pi)**3 / (nkbz * cryst%ucvol)
    1537              :  ! radius that gives the same volume as q0_volsph
    1538              :  ! Let's assume that c is perpendicular to the plane
    1539              :  ! We also assume isotropic BZ around gamma
    1540            0 :  step=sqrt((q0_volsph/bz_plane)/pi)/npt
    1541              : 
    1542              :  !step=half/(npt*(nqibz-1))
    1543              :  ! Let's take qpoints along 1 line, the vcut does depend only on the norm
    1544            0 :  qcart(1,:) = arth(tol6,step,npt)
    1545              : 
    1546            0 :  do ii=1,npt
    1547            0 :    qfit(:,ii) = MATMUL(TRANSPOSE(Cryst%rprimd),qcart(:,ii)) / (2*pi)
    1548              :    call cutoff_slab(qfit(:,ii), 1, gamma_pt, cryst%gprimd, rcut, &
    1549            0 :                     boxcenter, pdir, alpha, vcfit(:,ii), opt_slab)
    1550              :  end do
    1551              : 
    1552            0 :  ABI_MALLOC(xx, (npt))
    1553            0 :  ABI_MALLOC(yy, (npt))
    1554            0 :  ABI_MALLOC(sigma, (npt))
    1555            0 :  do ii=1,npt
    1556              :    !xx(ii)=qfit(1,:)
    1557            0 :    xx(ii) = normv(qfit(:,ii), cryst%gmet, 'G')
    1558              :  end do
    1559            0 :  ABI_FREE(qfit)
    1560            0 :  sigma=one
    1561            0 :  yy(:)=vcfit(1,:)
    1562              :  !yy(:)=one
    1563            0 :  ABI_FREE(vcfit)
    1564              : 
    1565            0 :  dx=(xx(2)-xx(1))
    1566              :  ! integ = \int dr r f(r)
    1567            0 :  integ=xx(2)*yy(2)*dx*3.0/2.0
    1568            0 :  integ=integ+DOT_PRODUCT(xx(3:npt-2),yy(3:npt-2))*dx
    1569            0 :  integ=integ+xx(npt-1)*yy(npt-1)*dx*3.0/2.0
    1570              :  !write(std_out,*)' simple integral',integ
    1571            0 :  q0_vol=bz_plane*pi*xx(npt)**2
    1572              :  !write(std_out,*)' q0 sphere : ',q0_volsph,' q0_vol cyl ',q0_vol
    1573            0 :  i_sz=bz_plane*2*pi*integ/q0_vol
    1574              :  !write(std_out,*)' spherical approximation ',four_pi*7.44*q0_volsph**(-two_thirds)
    1575              :  !write(std_out,*)' Cylindrical cutoff value ',i_sz
    1576              :  !i_sz=four_pi*7.44*q0_vol**(-two_thirds)
    1577            0 :  ABI_FREE(xx)
    1578            0 :  ABI_FREE(yy)
    1579              : 
    1580            0 : end subroutine beigi_surface_limit
    1581              : !!***
    1582              : 
    1583              : !!****f* m_vcoul/carrier_isz
    1584              : !! NAME
    1585              : !!  carrier_isz
    1586              : !!
    1587              : !! FUNCTION
    1588              : !!
    1589              : !! SOURCE
    1590              : 
    1591          210 : real(dp) function carrier_isz(cryst, nqbz, qbz, rcut, comm) result(i_sz)
    1592              : 
    1593              : !Arguments ------------------------------------
    1594              :  type(crystal_t),intent(in) :: cryst
    1595              :  integer,intent(in) :: nqbz, comm
    1596              :  real(dp), intent(in) :: qbz(3, nqbz), rcut
    1597              : 
    1598              : !Local variables-------------------------------
    1599              :  integer :: iq_bz
    1600              :  real(dp) :: qbz_norm, bz_geometry_factor, qbz_cart(3), b1(3), b2(3), b3(3)
    1601              : !************************************************************************
    1602              : 
    1603         2100 :  b1 = two_pi * cryst%gprimd(:,1); b2 = two_pi * cryst%gprimd(:,2); b3 = two_pi * cryst%gprimd(:,3)
    1604              : 
    1605              :  bz_geometry_factor = zero
    1606         9777 :  do iq_bz=1,nqbz
    1607        38268 :    qbz_cart(:) = qbz(1,iq_bz)*b1(:) + qbz(2,iq_bz)*b2(:) + qbz(3,iq_bz)*b3(:)
    1608        38268 :    qbz_norm = NORM2(qbz_cart(:))
    1609         9777 :    if (qbz_norm > TOLQ0) bz_geometry_factor = bz_geometry_factor - faux(qbz(:,iq_bz), rcut, b1, b2, b3)
    1610              :  end do
    1611              : 
    1612          210 :  bz_geometry_factor = bz_geometry_factor + integratefaux(rcut, cryst%gprimd, cryst%ucvol, comm) * nqbz
    1613          210 :  i_sz = four_pi * bz_geometry_factor  ! Final result stored here
    1614              : 
    1615          210 : end function carrier_isz
    1616              : !!***
    1617              : 
    1618              : !!****f* m_vcoul/gygi_baldereschi_isz
    1619              : !! NAME
    1620              : !!  gygi_baldereschi_isz
    1621              : !!
    1622              : !! FUNCTION
    1623              : !!
    1624              : !! SOURCE
    1625              : 
    1626            8 : real(dp) function gygi_baldereschi_isz(cryst, nqbz, qbz, vc_ecut, ng, gvec) result(i_sz)
    1627              : 
    1628              : !Arguments ------------------------------------
    1629              :  type(crystal_t),intent(in) :: cryst
    1630              :  integer,intent(in) :: nqbz, ng
    1631              :  real(dp), intent(in) :: qbz(3, nqbz), vc_ecut
    1632              :  integer,intent(in) :: gvec(3,ng)
    1633              : 
    1634              : !Local variables-------------------------------
    1635              :  integer :: iq_bz, ig
    1636              :  real(dp) :: bz_geometry_factor, intfauxgb, alfa, qpg2, qpg(3)
    1637              : !************************************************************************
    1638              : 
    1639              :  ! the choice of alfa (the width of the gaussian) is somehow empirical
    1640            8 :  alfa = 150.0 / vc_ecut
    1641              : 
    1642            8 :  bz_geometry_factor=zero
    1643          224 :  do iq_bz=1,nqbz
    1644        59192 :    do ig = 1,ng
    1645       235872 :      qpg(:) = qbz(:,iq_bz) + gvec(:,ig)
    1646        58968 :      qpg2 = normv(qpg, cryst%gmet, 'G')**2
    1647        59184 :      if (qpg2 > TOLQ0) bz_geometry_factor = bz_geometry_factor - EXP(-alfa*qpg2)/qpg2
    1648              :    end do
    1649              :  end do
    1650              : 
    1651            8 :  intfauxgb = cryst%ucvol/four_pi/SQRT(0.5*two_pi*alfa)
    1652            8 :  bz_geometry_factor = bz_geometry_factor + intfauxgb * nqbz
    1653              : 
    1654            8 :  i_sz = four_pi*bz_geometry_factor
    1655              : 
    1656            8 : end function gygi_baldereschi_isz
    1657              : !!***
    1658              : 
    1659              : !----------------------------------------------------------------------
    1660              : 
    1661              : !!****f* m_vcoul/vcgen_init
    1662              : !! NAME
    1663              : !! vcgen_init
    1664              : !!
    1665              : !! FUNCTION
    1666              : !!
    1667              : !! SOURCE
    1668              : 
    1669            0 : subroutine vcgen_init(vcgen, cryst, kptrlatt, nkbz, nqibz, nqbz, qbz, rcut, gw_icutcoul, vcutgeo, vc_ecut, comm)
    1670              : 
    1671              : !Arguments ------------------------------------
    1672              :  class(vcgen_t),intent(out) :: vcgen
    1673              :  type(crystal_t),intent(in) :: cryst
    1674              :  integer,intent(in) :: kptrlatt(3,3), nkbz, nqibz, nqbz, gw_icutcoul
    1675              :  real(dp),intent(in) :: qbz(3,nqbz), rcut, vc_ecut, vcutgeo(3)
    1676              :  integer,intent(in) :: comm
    1677              : 
    1678              : !Local variables-------------------------------
    1679              :  integer,parameter :: istwfk1 = 1
    1680              :  integer :: gvec0(3) ! npw_,
    1681              :  real(dp) :: q0_vol, bz_geometry_factor, rcut2
    1682              :  character(len=500) :: msg
    1683              :  real(dp) :: vcoul0(1), q_gamma(3)
    1684              :  !integer,allocatable :: gvec_(:,:)
    1685              : ! *************************************************************************
    1686              : 
    1687              :  ABI_UNUSED([vc_ecut])
    1688              : 
    1689              :  ! Save dimension and other useful quantities in Vcp
    1690            0 :  vcgen%rcut      = rcut                 ! Cutoff radius for cylinder.
    1691            0 :  vcgen%hcyl      = zero                 ! Length of finite cylinder (Rozzi's method, default is Beigi).
    1692            0 :  vcgen%boxcenter = zero                 ! Boxcenter at the moment is supposed to be at the origin.
    1693            0 :  vcgen%vcutgeo   = vcutgeo(:)           ! Info on the orientation and extension of the cutoff region.
    1694            0 :  vcgen%nkbz      = nkbz
    1695              : 
    1696            0 :  call gw_icutcoul_to_mode(gw_icutcoul, vcgen%mode)
    1697            0 :  q_gamma = zero
    1698            0 :  gvec0 = 0
    1699              : 
    1700            0 :  select case (trim(vcgen%mode))
    1701              :  case ('MINIBZ', 'MINIBZ-ERFC', 'MINIBZ-ERF')
    1702            0 :    call vcgen%mc%init(cryst%rprimd, cryst%ucvol, cryst%gprimd, cryst%gmet, kptrlatt)
    1703            0 :    rcut2 = vcgen%rcut**2
    1704            0 :    call vcgen%mc%integrate(vcgen%mode, q_gamma, 1, gvec0, rcut2, nkbz, vcoul0, xmpi_comm_self)
    1705              :    ! Treat the limit q --> 0.
    1706            0 :    vcgen%i_sz = vcoul0(1)
    1707              : 
    1708              :  case ('SPHERE')
    1709              :    ! A non-positive value of rcut activates the recipe of Spencer & Alavi, PRB 77, 193110 (2008) [[cite:Spencer2008]].
    1710            0 :    if (vcgen%rcut < tol12) then
    1711            0 :      vcgen%rcut = (cryst%ucvol * nkbz * 3.d0 / four_pi) ** third
    1712            0 :      write(msg,'(2a,2x,f8.4,a)')ch10,' Using calculated rcut: ',vcgen%rcut,' to have same volume as the BvK crystal'
    1713            0 :      call wrtout(std_out, msg)
    1714              :    end if
    1715            0 :    vcgen%vcutgeo = zero
    1716              : 
    1717              :    ! Treat the limit q --> 0
    1718              :    ! The small cube is approximated by a sphere, while vc(q=0) = 2piR**2.
    1719              :    ! if a single q-point is used, the expression for the volume is exact.
    1720            0 :    vcgen%i_sz = two_pi * vcgen%rcut**2
    1721              : 
    1722              :  case ('CYLINDER')
    1723            0 :    call cylinder_setup(cryst, vcgen%vcutgeo, vcgen%hcyl, vcgen%pdir, vcgen%opt_cylinder)
    1724              : 
    1725              :    ! If Beigi, treat the limit q --> 0.
    1726            0 :    if (vcgen%opt_cylinder == 1) then
    1727              :      call beigi_cylinder_limit(vcgen%opt_cylinder, cryst, nqibz, nkbz, &
    1728            0 :                                vcgen%rcut, vcgen%hcyl, vcgen%boxcenter, vcgen%pdir, vcgen%i_sz)
    1729              :    else
    1730              :      ! In Rozzi's method the lim q+G --> 0 is finite.
    1731              :      call cutoff_cylinder(q_gamma, 1, gvec0, vcgen%rcut, vcgen%hcyl, vcgen%pdir,&
    1732            0 :                           vcgen%boxcenter, cryst%rprimd, vcoul0, vcgen%opt_cylinder, xmpi_comm_self)
    1733            0 :      vcgen%i_sz = vcoul0(1)
    1734              :    end if
    1735              : 
    1736              :  case ('SLAB')
    1737            0 :    call surface_setup(cryst, vcgen%vcutgeo, vcgen%alpha, vcgen%rcut, vcgen%pdir, vcgen%opt_slab)
    1738              : 
    1739              :    ! If Beigi, treat the limit q --> 0.
    1740            0 :    if (vcgen%opt_slab == 1) then
    1741              :      ! Integrate numerically in the plane close to 0
    1742              :      call beigi_surface_limit(vcgen%opt_slab, cryst, nqibz, nkbz, vcgen%rcut, vcgen%alpha, &
    1743            0 :                               vcgen%boxcenter, vcgen%pdir, vcgen%i_sz)
    1744              :    else
    1745              :      ! In Rozzi's method the lim q+G --> 0 is finite.
    1746              :      call cutoff_slab(q_gamma, 1, gvec0, cryst%gprimd, vcgen%rcut, &
    1747            0 :                       vcgen%boxcenter, vcgen%pdir, vcgen%alpha, vcoul0, vcgen%opt_slab)
    1748            0 :      vcgen%i_sz = vcoul0(1)
    1749              :    end if
    1750              : 
    1751              :  case ('CRYSTAL', 'AUXILIARY_FUNCTION', "AUX_GB")
    1752              : 
    1753            0 :    if (vcgen%mode == "CRYSTAL") then
    1754              :      ! Analytic integration of 4pi/q^2 over the volume element:
    1755              :      ! $4pi/V \int_V d^3q 1/q^2 =4pi bz_geometric_factor V^(-2/3)$
    1756              :      ! i_sz=4*pi*bz_geometry_factor*q0_vol**(-two_thirds) where q0_vol= V_BZ/N_k
    1757              :      ! bz_geometry_factor: sphere=7.79, fcc=7.44, sc=6.188, bcc=6.946, wz=5.255 (see gwa.pdf, appendix A.4)
    1758            0 :      q0_vol = (two_pi) **3 / (nkbz*cryst%ucvol); bz_geometry_factor=zero
    1759            0 :      vcgen%i_sz = four_pi*7.44*q0_vol**(-two_thirds)
    1760              : 
    1761            0 :    else if (vcgen%mode == "AUXILIARY_FUNCTION") then
    1762              :      ! Numerical integration of the exact-exchange divergence through the
    1763              :      ! auxiliary function of Carrier et al. PRB 75, 205126 (2007) [[cite:Carrier2007]].
    1764            0 :      vcgen%i_sz = carrier_isz(cryst, nqbz, qbz, rcut, comm)
    1765              : 
    1766            0 :    else if (vcgen%mode == "AUX_GB") then
    1767              :      ! We use the auxiliary function of a Gygi-Baldereschi variant [[cite:Gigy1986]]
    1768              :      ! TODO:
    1769            0 :      ABI_ERROR("AUX_GB not implemented in vcgen_init")
    1770              :      !call get_kg(kk_bz, istwfk1, vc_ecut, cryst%gmet, npw_, gvec_)
    1771              :      !vcgen%i_sz = gygi_baldereschi_isz(cryst, nqbz, qbz, vc_ecut, ng, gvec_)
    1772              :      !ABI_FREE(gvec_)
    1773              : 
    1774              :    else
    1775            0 :      ABI_ERROR(sjoin("Need treatment of 1/q^2 singularity! for mode", vcgen%mode))
    1776              :    end if
    1777              : 
    1778              :  case ('ERF')
    1779            0 :    vcgen%i_sz = carrier_isz(cryst, nqbz, qbz, rcut, xmpi_comm_self)
    1780              : 
    1781              :  case ('ERFC')
    1782              :    ! === Treat 1/q^2 singularity ===
    1783              :    ! * There is NO singularity in this case.
    1784            0 :    vcgen%i_sz = pi * vcgen%rcut**2 ! Final result stored here
    1785              : 
    1786              :  case default
    1787            0 :    ABI_BUG(sjoin('Unsupported cutoff mode:', vcgen%mode))
    1788              :  end select
    1789              : 
    1790              :  !call wrtout(std_out, sjoin(" vcgen%i_sz", ftoa(vcgen%i_sz)))
    1791              : 
    1792            0 : end subroutine vcgen_init
    1793              : !!***
    1794              : 
    1795              : !----------------------------------------------------------------------
    1796              : 
    1797              : !!****f* m_vcoul/vcgen_get_vc_sqrt
    1798              : !! NAME
    1799              : !! vcgen_get_vc_sqrt
    1800              : !!
    1801              : !! FUNCTION
    1802              : !!  Compute sqrt(vc(q, g))
    1803              : !!
    1804              : !! SOURCE
    1805              : 
    1806            0 : subroutine vcgen_get_vc_sqrt(vcgen, qpt, npw, gvec, q0, cryst, vc_sqrt, comm, &
    1807            0 :                              vc) ! optional
    1808              : 
    1809              : !Arguments ------------------------------------
    1810              :  class(vcgen_t),intent(in) :: vcgen
    1811              :  real(dp),intent(in) :: qpt(3), q0(3)
    1812              :  integer,intent(in) :: npw, gvec(3,npw), comm
    1813              :  type(crystal_t),intent(in) :: cryst
    1814              :  complex(gwp),intent(out) :: vc_sqrt(npw)
    1815              :  real(dp),optional,intent(out) :: vc(npw)
    1816              : 
    1817              : !Local variables-------------------------------
    1818              :  integer :: ig, ig0
    1819              :  real(dp) :: rcut2
    1820              :  logical :: q_is_gamma
    1821            0 :  real(dp),allocatable :: vcoul(:)
    1822              : ! *************************************************************************
    1823              : 
    1824            0 :  q_is_gamma = normv(qpt, cryst%gmet, "G") < GW_TOLQ0
    1825              : 
    1826              :  ! Find the index of G=0 in gvec.
    1827            0 :  ig0 = -1
    1828            0 :  do ig=1,npw
    1829            0 :    if (all(gvec(:,ig) == 0)) then
    1830              :     ig0 = ig; exit
    1831              :    end if
    1832              :  end do
    1833            0 :  ABI_CHECK(ig0 /= -1, "Cannot find G=0 in gvec!")
    1834              : 
    1835            0 :  ABI_MALLOC(vcoul, (npw))
    1836              : 
    1837            0 :  select case (trim(vcgen%mode))
    1838              :  case ('MINIBZ', 'MINIBZ-ERFC', 'MINIBZ-ERF')
    1839            0 :    rcut2 = vcgen%rcut**2
    1840            0 :    call vcgen%mc%integrate(vcgen%mode, qpt, npw, gvec, rcut2, vcgen%nkbz, vcoul, comm)
    1841              : 
    1842              :  case ('SPHERE')
    1843            0 :    call cutoff_sphere(qpt, npw, gvec, cryst%gmet, vcgen%rcut, vcoul)
    1844              : 
    1845              :  case ('CYLINDER')
    1846              :    call cutoff_cylinder(qpt, npw, gvec, vcgen%rcut, vcgen%hcyl, vcgen%pdir, &
    1847            0 :                         vcgen%boxcenter, cryst%rprimd, vcoul, vcgen%opt_cylinder, comm)
    1848              : 
    1849              :  case ('SLAB')
    1850              :    call cutoff_slab(qpt, npw, gvec, cryst%gprimd, vcgen%rcut, &
    1851            0 :                     vcgen%boxcenter, vcgen%pdir, vcgen%alpha, vcoul, vcgen%opt_slab)
    1852              : 
    1853              :  case ('CRYSTAL', 'AUXILIARY_FUNCTION', "AUX_GB", "ERF", "ERFC")
    1854              :    ! Compute |q+G| with special treatment of (q=0, g=0).
    1855            0 :    do ig=1,npw
    1856            0 :      if (q_is_gamma .and. ig == ig0) then
    1857            0 :        vcoul(ig) = normv(q0 + gvec(:,ig), cryst%gmet, "G")
    1858              :        !print *, "q_is_gamma with ", q0, "and vcoul:", vcoul(ig); stop
    1859              :      else
    1860            0 :        vcoul(ig) = normv(qpt + gvec(:,ig), cryst%gmet, "G")
    1861              :      end if
    1862              :    end do
    1863              : 
    1864            0 :    if (vcgen%mode == "ERF") then
    1865            0 :      vcoul(:) = four_pi/(vcoul(:)**2) *  EXP( -0.25d0 * (vcgen%rcut*vcoul(:))**2 )
    1866            0 :    else if (vcgen%mode == "ERFC") then
    1867            0 :      vcoul(:) = four_pi/(vcoul(:)**2) * ( one - EXP( -0.25d0 * (vcgen%rcut*vcoul(:))**2 ) )
    1868              :    else
    1869            0 :      vcoul = four_pi/vcoul**2
    1870              :    end if
    1871              : 
    1872              :  case default
    1873            0 :    ABI_BUG(sjoin('Unsupported cutoff mode:', vcgen%mode))
    1874              :  end select
    1875              : 
    1876              :  ! Store final results in complex array as Rozzi's cutoff can give real negative values
    1877            0 :  vc_sqrt = sqrt(cmplx(vcoul, zero))
    1878              : 
    1879            0 :  if (present(vc)) vc = vcoul
    1880            0 :  ABI_FREE(vcoul)
    1881              : 
    1882            0 : end subroutine vcgen_get_vc_sqrt
    1883              : !!***
    1884              : 
    1885              : !----------------------------------------------------------------------
    1886              : 
    1887              : !!****f* m_vcoul/vcgen_free
    1888              : !! NAME
    1889              : !! vcgen_free
    1890              : !!
    1891              : !! FUNCTION
    1892              : !!  Free dynamic memory.
    1893              : !!
    1894              : !! SOURCE
    1895              : 
    1896            0 : subroutine vcgen_free(vcgen)
    1897              : 
    1898              : !Arguments ------------------------------------
    1899              :  class(vcgen_t),intent(inout) :: vcgen
    1900              : ! *************************************************************************
    1901              : 
    1902            0 :  call vcgen%mc%free()
    1903              : 
    1904            0 : end subroutine vcgen_free
    1905              : !!***
    1906              : 
    1907              : !----------------------------------------------------------------------
    1908              : 
    1909              : !!****f* m_vcoul/vcgen_print
    1910              : !! NAME
    1911              : !! vcgen_print
    1912              : !!
    1913              : !! FUNCTION
    1914              : !!  Print info on the object.
    1915              : !!
    1916              : !! SOURCE
    1917              : 
    1918            0 : subroutine vcgen_print(vcgen, units, header, prtvol)
    1919              : 
    1920              : !Arguments ------------------------------------
    1921              :  class(vcgen_t),intent(in) :: vcgen
    1922              :  integer,intent(in) :: units(:), prtvol
    1923              :  character(len=*),intent(in) :: header
    1924              : 
    1925              : !Local variables-------------------------------
    1926              : !scalars
    1927              :  integer :: ii
    1928              :  character(len=500) :: msg
    1929              : ! *************************************************************************
    1930              : 
    1931              :  ABI_UNUSED(prtvol)
    1932              : 
    1933            0 :  msg = ch10//' === '//trim(adjustl(header))//' === '
    1934            0 :  call wrtout(units, msg)
    1935              : 
    1936            0 :  select case (vcgen%mode)
    1937              : 
    1938              :  case ('MINIBZ')
    1939            0 :    write(msg,'(3a)')ch10,' cutoff-mode = ',trim(vcgen%mode)
    1940            0 :    call wrtout(units, msg)
    1941              : 
    1942              :  case ('MINIBZ-ERF')
    1943            0 :    write(msg,'(3a)')ch10,' cutoff-mode = ',trim(vcgen%mode)
    1944            0 :    call wrtout(units, msg)
    1945            0 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    1946            0 :      ' === Error function cutoff === ',ch10,ch10,&
    1947            0 :      '  Cutoff radius ......... ',vcgen%rcut,' [Bohr] ',ch10
    1948            0 :    call wrtout(units, msg)
    1949              : 
    1950              :  case ('MINIBZ-ERFC')
    1951            0 :    write(msg,'(3a)')ch10,' cutoff-mode = ',trim(vcgen%mode)
    1952            0 :    call wrtout(units, msg)
    1953            0 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    1954            0 :      ' === Complement Error function cutoff === ',ch10,ch10,&
    1955            0 :      '  Cutoff radius ......... ',vcgen%rcut,' [Bohr] ',ch10
    1956            0 :    call wrtout(units, msg)
    1957              : 
    1958              :  case ('SPHERE')
    1959            0 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    1960            0 :     ' === Spherical cutoff === ',ch10,ch10,&
    1961            0 :     '  Cutoff radius ......... ',vcgen%rcut,' [Bohr] ',ch10,&
    1962            0 :     '  Volume of the sphere .. ',four_pi/three*vcgen%rcut**3,' [Bohr^3] '
    1963              :     !FB: This has no meaning here! &  '  Sphere centered at .... ',vcgen%boxcenter,' (r.l.u) ',ch10
    1964              :     !MG It might be useful if the system is not centered on the origin because in this case the
    1965              :     !   matrix elements of the Coulomb have to be multiplied by a phase depending on boxcenter.
    1966              :     !   I still have to decide if it is useful to code this possibility and which variable use to
    1967              :     !   define the center (boxcenter is used in the tddft part).
    1968            0 :    call wrtout(units, msg)
    1969              : 
    1970              :  case ('CYLINDER')
    1971            0 :    ii=imin_loc(ABS(vcgen%pdir-1))
    1972            0 :    write(msg,'(5a,f10.4,3a,i2,2a,3f10.2,a)')ch10,&
    1973            0 :      ' === Cylindrical cutoff === ',ch10,ch10,&
    1974            0 :      '  Cutoff radius ............... ',vcgen%rcut,' [Bohr] ',ch10,&
    1975            0 :      '  Axis parallel to direction... ',ii,ch10,&
    1976            0 :      '  Passing through point ....... ',vcgen%boxcenter,' (r.l.u) '
    1977            0 :    call wrtout(units, msg)
    1978              : 
    1979            0 :    write(msg,'(2a)')'  Infinite length  ....... ',ch10
    1980            0 :    if (vcgen%hcyl/=zero) write(msg,'(a,f8.5,2a)')'  Finite length of ....... ',vcgen%hcyl,' [Bohr] ',ch10
    1981            0 :    call wrtout(units, msg)
    1982              : 
    1983              :  CASE ('SLAB')
    1984            0 :    write(msg,'(5a,f10.4,3a,3f10.2,2a)')ch10,&
    1985            0 :      ' === Surface cutoff === ',ch10,ch10,&
    1986            0 :      '  Cutoff radius .................... ',vcgen%rcut,' [Bohr] ',ch10,&
    1987            0 :      '  Central plane passing through .... ',vcgen%boxcenter,' (r.l.u) ',ch10
    1988            0 :    call wrtout(units, msg)
    1989              :    !write(msg,'(a)')'  Infinite length  .......'
    1990              :    !if (vcgen%hcyl/=zero) write(msg,'(a,f8.5,a)')'  Finite length of .......',vcgen%hcyl,' [Bohr] '
    1991              :    !call wrtout(units, msg)
    1992              : 
    1993              :  case ('AUXILIARY_FUNCTION')
    1994            0 :    write(msg,'(3a)')ch10,' cutoff-mode = ',trim(vcgen%mode)
    1995            0 :    call wrtout(units, msg)
    1996              : 
    1997              :  case ('AUX_GB')
    1998            0 :    write(msg,'(3a)')ch10,' cutoff-mode = ',trim(vcgen%mode)
    1999            0 :    call wrtout(units, msg)
    2000              : 
    2001              :  case ('CRYSTAL')
    2002            0 :    write(msg,'(3a)')ch10,' cutoff-mode = ',trim(vcgen%mode)
    2003            0 :    call wrtout(units, msg)
    2004              : 
    2005              :  case ('ERF')
    2006            0 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    2007            0 :      ' === Error function cutoff === ',ch10,ch10,&
    2008            0 :      '  Cutoff radius ......... ',vcgen%rcut,' [Bohr] ',ch10
    2009            0 :    call wrtout(units, msg)
    2010              : 
    2011              :  case ('ERFC')
    2012            0 :    write(msg,'(5a,f10.4,3a,f10.2,3a,3f10.5,2a)')ch10,&
    2013            0 :      ' === Complement Error function cutoff === ',ch10,ch10,&
    2014            0 :      '  Cutoff radius ......... ',vcgen%rcut,' [Bohr] ',ch10
    2015            0 :    call wrtout(units, msg)
    2016              : 
    2017              :  case default
    2018            0 :    ABI_BUG(sjoin('Unknown cutoff mode: ', vcgen%mode))
    2019              :  end select
    2020              : 
    2021              :  !if (vcgen%nqlwl > 0) then
    2022              :  !  write(msg,'(a,i3)')" q-points for optical limit: ",vcgen%nqlwl
    2023              :  !  call wrtout(units, msg)
    2024              :  !  do iqlwl=1,vcgen%nqlwl
    2025              :  !    write(msg,'(1x,i5,a,2x,3f12.6)') iqlwl,')',vcgen%qlwl(:,iqlwl)
    2026              :  !    call wrtout(units, msg)
    2027              :  !  end do
    2028              :  !end if
    2029              : 
    2030            0 : end subroutine vcgen_print
    2031              : !!***
    2032              : 
    2033         1218 : end module m_vcoul
    2034              : !!***
        

Generated by: LCOV version 2.3-1