LCOV - code coverage report
Current view: top level - src/62_poisson - m_psolver.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 14 0
Test Date: 2026-09-21 13:49:52 Functions: 0.0 % 3 0

            Line data    Source code
       1              : !!****m* ABINIT/m_psolver
       2              : !! NAME
       3              : !!  m_psolver
       4              : !!
       5              : !! FUNCTION
       6              : !!  Poisson solver
       7              : !!
       8              : !! COPYRIGHT
       9              : !!  Copyright (C) 1998-2026 ABINIT group (DCA, XG, GMR,TRangel).
      10              : !!  This file is distributed under the terms of the
      11              : !!  GNU General Public License, see ~abinit/COPYING
      12              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      13              : !!
      14              : !! SOURCE
      15              : 
      16              : #if defined HAVE_CONFIG_H
      17              : #include "config.h"
      18              : #endif
      19              : 
      20              : #include "abi_common.h"
      21              : 
      22              : module m_psolver
      23              : 
      24              :  use defs_basis
      25              :  use defs_wvltypes
      26              :  use m_abicore
      27              :  use m_errors
      28              :  use m_abi2big
      29              :  use m_cgtools
      30              :  use m_xmpi
      31              : 
      32              :  use defs_abitypes, only : mpi_type
      33              :  use m_geometry, only : metric
      34              :  use m_drivexc,  only : mkdenpos
      35              : 
      36              :  implicit none
      37              : 
      38              :  private
      39              : !!***
      40              : 
      41              :  public :: psolver_rhohxc
      42              :  public :: psolver_hartree
      43              :  public :: psolver_kernel
      44              : !!***
      45              : 
      46              : contains
      47              : !!***
      48              : 
      49              : !!****f* ABINIT/psolver_rhohxc
      50              : !! NAME
      51              : !! psolver_rhohxc
      52              : !!
      53              : !! FUNCTION
      54              : !! Given rho(r), compute Hartree potential considering the system as
      55              : !! an isolated one. This potential is obtained from the convolution
      56              : !! of 1/r and rho(r), treated in Fourier space. This method is a wrapper around
      57              : !! Psolver() developped for BigDFT.
      58              : !! It can compute the xc energy and potential if required. This computation is
      59              : !! built on the drivexc() routine of ABINIT but access it directly from real
      60              : !! space. The present routine is a real space counter part to rhotoxc().
      61              : !!
      62              : !! INPUTS
      63              : !!  dtset <type(dataset_type)>=all input variables in this dataset
      64              : !!  mpi_enreg=MPI-parallelisation information.
      65              : !!  rhor(nfft,nspden)=electron density in real space in electrons/bohr**3
      66              : !!
      67              : !! OUTPUT
      68              : !!  enhartr=returned Hartree energy (hartree).
      69              : !!  enxc=returned exchange and correlation energy (hartree).
      70              : !!  envxc=returned energy of the Vxc potential (hartree).
      71              : !!  vhartr(nfft)=Hartree potential.
      72              : !!  vxc(nfft,nspden)=xc potential
      73              : !!  vxcavg=<Vxc>=unit cell average of Vxc = (1/ucvol) Int [Vxc(r) d^3 r].
      74              : !!
      75              : !! NOTE
      76              : !!  In psolver, with nspden == 2, rhor(:,1) = density up and
      77              : !!                                rhor(:,2) = density down.
      78              : !!  But in ABINIT (dtset%usewvl != 1) rhor(:,1) = total density and
      79              : !!                                    rhor(:,2) = density up .
      80              : !!  In ABINIT (dtset%usewvl != 1), the same convention is used as in psolver.
      81              : !!
      82              : !! SOURCE
      83              : 
      84            0 : subroutine psolver_rhohxc(enhartr, enxc, envxc, icoulomb, ixc, &
      85            0 : & mpi_enreg, nfft, ngfft, nhat,nhatdim,&
      86            0 : & nscforder, nspden, n3xccc, rhor, rprimd,&
      87            0 : & usexcnhat,usepaw,usewvl,vhartr, vxc, vxcavg, wvl,wvl_den,wvl_e,&
      88            0 : & xccc3d,xclevel,xc_denpos)
      89              : 
      90              : #if defined HAVE_BIGDFT
      91              :  use BigDFT_API, only : XC_potential,ELECTRONIC_DENSITY,coulomb_operator
      92              :  use poisson_solver, only : H_potential
      93              : #endif
      94              : 
      95              :   !Arguments ------------------------------------
      96              :   !scalars
      97              :   integer, intent(in)           :: nhatdim,nspden,n3xccc
      98              :   integer, intent(in)           :: nfft, icoulomb, ixc, nscforder, usewvl
      99              :   integer,intent(in)            :: usexcnhat,usepaw,xclevel
     100              :   real(dp),intent(in)           :: rprimd(3,3)
     101              :   real(dp), intent(in)          :: xc_denpos
     102              :   real(dp), intent(out)         :: enxc, envxc, enhartr, vxcavg
     103              :   type(mpi_type), intent(in) :: mpi_enreg
     104              :   type(wvl_internal_type), intent(in) :: wvl
     105              :   type(wvl_denspot_type), intent(inout) :: wvl_den
     106              :   type(wvl_energy_terms), intent(inout) :: wvl_e
     107              :   !arrays
     108              :   integer, intent(in)    :: ngfft(18)
     109              :   real(dp),intent(in) :: xccc3d(n3xccc)
     110              :   real(dp),intent(in) :: nhat(nfft,nspden*nhatdim)
     111              :   real(dp),intent(inout) :: rhor(nfft, nspden)
     112              :   real(dp),intent(out)   :: vhartr(nfft)
     113              :   real(dp),intent(out)   :: vxc(nfft, nspden)
     114              : 
     115              :   !Local variables-------------------------------
     116              : #if defined HAVE_BIGDFT
     117              : ! n_c and \hat{n} can be added/rested inside bigdft by passing
     118              : ! them as pointers (rhocore and rhohat):
     119              :   logical, parameter :: add_n_c_here=.true.  !Add n_c here or inside bigdft
     120              :   logical, parameter :: rest_hat_n_here=.true.  !Rest \hat{n} here or inside bigdft
     121              :   !scalars
     122              :   integer :: me,nproc,comm
     123              :   integer :: ifft,ispin
     124              :   integer :: iwarn, opt_mkdenpos
     125              :   integer :: nfftot,ngrad
     126              :   integer :: n1i,n2i,n3d,n3i
     127              :   real(dp) :: tmpDown, tmpUp, tmpPot,ucvol,ucvol_local
     128              :   logical :: sumpion,test_nhat,use_psolver=.false.
     129              :   character(len=500) :: message
     130              :   character(len = 1) :: datacode, bndcode
     131              :   !arrays
     132              :   real(dp) :: gmet(3,3),gprimd(3,3),rmet(3,3)
     133              :   real(dp) :: hgrid(3)
     134              :   real(dp) :: vxcmean(1)
     135              :   real(dp), pointer :: rhocore(:,:,:,:),rhohat(:,:,:,:)
     136              :   real(dp), pointer :: pot_ion(:,:,:,:),rhonow(:,:)
     137              :   real(dp), dimension(6) :: xcstr
     138              :   type(coulomb_operator) ::  kernel
     139              : #endif
     140              : 
     141              : ! *********************************************************************
     142              : 
     143              :  DBG_ENTER("COLL")
     144              : 
     145              : #if defined HAVE_BIGDFT
     146              : 
     147              :  nfftot=PRODUCT(ngfft(1:3))
     148              :  comm=mpi_enreg%comm_fft
     149              :  if(usewvl==1) comm=mpi_enreg%comm_wvl
     150              :  me=xmpi_comm_rank(comm)
     151              :  nproc=xmpi_comm_size(comm)
     152              : 
     153              :  if(n3xccc>0) then
     154              :    if(nfft .ne. n3xccc)then
     155              :      write(message,'(a,a,a,2(i0,1x))')&
     156              : &     'nfft and n3xccc should be equal,',ch10,&
     157              : &     'however, nfft and n3xccc=',nfft,n3xccc
     158              :      ABI_BUG(message)
     159              :    end if
     160              :  end if
     161              :  if(nspden==4) then
     162              :    ABI_ERROR('nspden==4 not coded yet')
     163              :  end if
     164              : 
     165              :  if (ixc==0) then
     166              :    vxcavg=zero
     167              :    test_nhat=.false.
     168              : 
     169              : !  No xc at all is applied (usually for testing)
     170              :    ABI_WARNING('Note that no xc is applied (ixc=0).')
     171              : 
     172              :  else if (ixc/=20) then
     173              : 
     174              : !  ngrad=1 is for LDAs or LSDs, ngrad=2 is for GGAs
     175              :    ngrad=1;if(xclevel==2)ngrad=2
     176              : !  ixc 31 to 35 are for mgga test purpose only (fake functionals based on LDA but need the gradients too)
     177              :    if(ixc>=31 .and. ixc<=35)ngrad=2
     178              : !  Test: has a compensation density to be added/substracted (PAW) ?
     179              : !  test_nhat=((nhatdim==1).and.(usexcnhat==0.or.(ngrad==2.and.nhatgrdim==1)))
     180              :    test_nhat=((nhatdim==1).and.(usexcnhat==0))
     181              :  end if
     182              : 
     183              : 
     184              : !Compute different geometric tensor, as well as ucvol, from rprimd
     185              :  call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
     186              : 
     187              :  if (icoulomb == 0) then
     188              : !  The kernel is built with 'P'eriodic boundary counditions.
     189              :    bndcode = 'P'
     190              :  else if (icoulomb == 1) then
     191              : !  The kernel is built with 'F'ree boundary counditions.
     192              :    bndcode = 'F'
     193              :  else if (icoulomb == 2) then
     194              : !  The kernel is built with 'S'urface boundary counditions.
     195              :    bndcode = 'S'
     196              :  end if
     197              : 
     198              : !This makes the tests fail?
     199              : !For NC and n_c=0, call psolver, which uses less memory:
     200              : !if(usepaw==0 .and. n3xccc==0) use_psolver=.true.
     201              : 
     202              :  if(nspden > 2)then
     203              :    write(message, '(a,a,a,i0)' )&
     204              : &   'Only non-spin-polarised or collinear spin is allowed,',ch10,&
     205              : &   'while the argument nspden = ', nspden
     206              :    ABI_ERROR(message)
     207              :  end if
     208              : 
     209              : !We do the computation.
     210              :  write(message, "(A,A,A,3I6)") "psolver_rhohxc(): compute potentials (Vhartree and Vxc)...", ch10, &
     211              : & " | dimension:", ngfft(1:3)
     212              :  call wrtout(std_out, message,'COLL')
     213              : 
     214              :  if(usewvl==1) then
     215              :    hgrid=(/wvl_den%denspot%dpbox%hgrids(1),wvl_den%denspot%dpbox%hgrids(2),wvl_den%denspot%dpbox%hgrids(3)/)
     216              :  else
     217              :    hgrid=(/ rprimd(1,1) / ngfft(1), rprimd(2,2) / ngfft(2), rprimd(3,3) / ngfft(3) /)
     218              :  end if
     219              : 
     220              :  if (usewvl == 0) then
     221              : !  We get the kernel.
     222              :    call psolver_kernel( hgrid, 2, icoulomb, me, kernel, comm, ngfft, nproc, nscforder)
     223              :  elseif(usewvl==1) then
     224              : !  In this case, the kernel is already computed.
     225              : !  We just shallow copy it.
     226              :    kernel = wvl_den%denspot%pkernel
     227              :  end if
     228              : 
     229              :  if(usewvl==1) then
     230              :    if(wvl_den%denspot%rhov_is .ne. ELECTRONIC_DENSITY) then
     231              :      message= "psolver_rhohxc: rhov should contain the electronic density"
     232              :      ABI_ERROR(message)
     233              :    end if
     234              :  end if
     235              : 
     236              :  if(usewvl==1) then
     237              :    n1i=wvl%Glr%d%n1i; n2i=wvl%Glr%d%n2i; n3i=wvl%Glr%d%n3i
     238              :    n3d=wvl_den%denspot%dpbox%n3d
     239              :  else
     240              :    n1i=ngfft(1); n2i=ngfft(2) ; n3i=ngfft(3)
     241              :    n3d=ngfft(13)
     242              :  end if
     243              : 
     244              :  if (usewvl == 0) then
     245              : !  ucvol_local=product(hgrid)*half**3*real(n1i*n2i*n3i,dp)
     246              : !  write(*,*)'hgrid, n1i,n2i,n3i',hgrid,ngfft(1:3)
     247              : !  write(*,*)'ucvol_local',ucvol_local
     248              :    ucvol_local = ucvol
     249              : !  write(*,*)'ucvol_local',ucvol_local
     250              :  else
     251              : !  We need to tune the volume when wavelets are used because, not
     252              : !  all FFT points are used.
     253              : !  ucvol_local = (half * dtset%wvl_hgrid) ** 3 * ngfft(1)*ngfft(2)*ngfft(3)
     254              :    ucvol_local = product(wvl_den%denspot%dpbox%hgrids) * real(product(wvl_den%denspot%dpbox%ndims), dp)
     255              :  end if
     256              : 
     257              : !Core density array
     258              :  if(n3xccc==0 .or. add_n_c_here) then
     259              :    nullify(rhocore)
     260              : !  Pending, next line should follow the same logic that the rest
     261              :    if(usewvl==1 .and. usepaw==0)  rhocore=> wvl_den%denspot%rho_C
     262              :  else
     263              :    if(usepaw==1) then
     264              :      ABI_MALLOC(rhocore,(n1i,n2i,n3d,1)) !not spin dependent
     265              :      call wvl_rhov_abi2big(1,xccc3d,rhocore)
     266              : 
     267              : !    Make rhocore positive to avoid numerical instabilities in V_xc
     268              :      iwarn=0 ; opt_mkdenpos=0
     269              :      call mkdenpos(iwarn, nfft, nspden, opt_mkdenpos, rhocore, tol20 )
     270              :    end if
     271              :  end if
     272              : 
     273              : !write(*,*)'psolver_rhohxc, erase me, set rhocore=0'
     274              : !if( associated(wvl_den%denspot%rho_C))wvl_den%denspot%rho_C=zero
     275              : !if(associated(rhocore))rhocore=zero
     276              : 
     277              : !Rhohat array:
     278              :  if(test_nhat .and. .not. rest_hat_n_here) then
     279              : !  rhohat => nhat !do not know how to point 4 index to 2 index
     280              : !  here we have to copy since convention for spin changes.
     281              :    ABI_MALLOC(rhohat,(n1i,n2i,n3d,nspden))
     282              :    call wvl_rhov_abi2big(1,nhat,rhohat)
     283              :  else
     284              :    nullify(rhohat)
     285              :  end if
     286              : 
     287              : !Data are always distributed when using the wavelets, even if nproc = 1.
     288              : !The size given is the complete size of the box, not the distributed size
     289              : !stored in ngfft.
     290              :  if (nproc > 1 .or. usewvl > 0) then
     291              :    datacode = 'D'
     292              :  else
     293              :    datacode = 'G'
     294              :  end if
     295              : 
     296              : !If usewvl=1, vpsp(or v_ext) will be summed to vhartree
     297              :  if(usewvl==1) then
     298              :    pot_ion=>wvl_den%denspot%V_ext
     299              :    sumpion=.false.
     300              : !  Note:
     301              : !  if sumpion==.true.
     302              : !  call wvl_newvtr in setvtr and rhotov
     303              : !  if sumpion==.false.
     304              : !  modify setvtr and rhotov to not use wvl_newvtr and follow the normal ABINIT flow.
     305              :  else
     306              : !  This is not allowed
     307              : !  pot_ion=>vxc !this is a dummy variable here
     308              :    sumpion=.false.
     309              :  end if
     310              : 
     311              : 
     312              : !To make this work, make sure that xc_init has been called
     313              : !in gstate.
     314              :  if(.not. use_psolver) then
     315              : !  T.Rangel:
     316              : !  Use this approach for PAW and sometimes for NC since
     317              : !  in psolver() the core density is not added.
     318              : !
     319              : !  PAW case:
     320              : !  It is important to call H_potential before XC_potential:
     321              : !  In XC_potential, if test_nhat, we do:
     322              : !  1) rhor=rhor-rhohat,
     323              : !  2) makepositive(rhor,tol20)
     324              : !  3) after Psolver, we do rhor=rhor+rhohat,
     325              : !  I found that rhor at input and output are slightly different,
     326              : !  These differences lead to a difference of ~0.01 hartree in V_hartree.
     327              : !  If PAW, substract compensation density from effective density:
     328              : !  - if GGA, because nhat gradients are computed separately
     329              : !  - if nhat does not have to be included in XC
     330              : 
     331              : !  save rhor in rhonow to avoid modifying it.
     332              :    ABI_MALLOC(rhonow,(nfft,nspden))
     333              : !  copy rhor into rhonow:
     334              : !  ABINIT convention is followed: (ispin=1: for spin up + spin down)
     335              :    rhonow(1:nfft,1:nspden)=abs(rhor(1:nfft,1:nspden))+1.0d-20
     336              : 
     337              :    if(usewvl==1) then
     338              :      call H_potential(datacode,&
     339              : &     kernel,rhonow,pot_ion,enhartr,&
     340              : &     zero,sumpion)
     341              :    else
     342              : !    Vxc is passed as a dummy argument
     343              :      call H_potential(datacode,&
     344              : &     kernel,rhonow,vxc,enhartr,&
     345              : &     zero,sumpion)
     346              :    end if
     347              : !
     348              :    vhartr(1:nfft)=rhonow(1:nfft,1)
     349              : !  write(*,*)'erase me psolver_rhohxc l350, set vhartr=0'
     350              : !  vhartr=zero ; enhartr=zero
     351              : !
     352              : !  Since rhonow was modified inside H_potential:
     353              : !  copy rhor again into rhonow following the BigDFT convention:
     354              :    call wvl_rhov_abi2big(1,rhor,rhonow)
     355              : 
     356              : !  Add n_c here:
     357              :    if(n3xccc>0 .and. add_n_c_here) then
     358              :      do ispin=1,nspden
     359              :        rhonow(:,ispin)=rhonow(:,ispin)+xccc3d(:)
     360              :      end do
     361              :    end if
     362              : !  Remove \hat{n} here:
     363              :    if(test_nhat .and. rest_hat_n_here) then
     364              :      rhonow(1:nfft,1:nspden)=rhonow(1:nfft,1:nspden)-nhat(1:nfft,1:nspden)
     365              :    end if
     366              : 
     367              : !  Make the density positive everywhere (but do not care about gradients)
     368              :    iwarn=0 ; opt_mkdenpos=0
     369              :    call mkdenpos(iwarn, nfft, nspden, opt_mkdenpos, rhonow, xc_denpos)
     370              : !  do ispin=1,nspden
     371              : !  do ifft=1,nfft
     372              : !  rhonow(ifft,ispin)=abs(rhonow(ifft,ispin))+1.0d-20
     373              : !  end do
     374              : !  end do
     375              : 
     376              : !  If PAW, substract compensation density from effective density:
     377              : !  - if GGA, because nhat gradients are computed separately
     378              : !  - if nhat does not have to be included in XC
     379              :    if (test_nhat .and. .not. rest_hat_n_here) then
     380              : 
     381              :      call XC_potential(bndcode,datacode,me,nproc,comm,&
     382              : &     n1i,n2i,n3i,&
     383              : &     wvl_den%denspot%xc,hgrid(1),hgrid(2),hgrid(3),&
     384              : &     rhonow,enxc,envxc,nspden,rhocore,&
     385              : &     vxc,xcstr,rhohat=rhohat)
     386              : 
     387              :    else
     388              : 
     389              :      call XC_potential(bndcode,datacode,me,nproc,comm,&
     390              : &     n1i,n2i,n3i,&
     391              : &     wvl_den%denspot%xc,hgrid(1),hgrid(2),hgrid(3),&
     392              : &     rhonow,enxc,envxc,nspden,rhocore,&
     393              : &     vxc,xcstr)
     394              : 
     395              :    end if
     396              : 
     397              : !  write(*,*)'psolver_rhohxc: erase me, set vxc=0'
     398              : !  vxc=zero
     399              : !  enxc=zero
     400              : !  envxc=zero
     401              : 
     402              : !  deallocate temporary array
     403              :    ABI_FREE(rhonow)
     404              : 
     405              :  else
     406              : !  NC case: here we optimize memory, and we reuse vhartree to store rhor:
     407              : 
     408              : !  We save total rhor in vhartr
     409              :    vhartr(1:nfft)  = rhor(1:nfft, 1)
     410              : 
     411              : !  In non-wavelet case, we change the rhor values.
     412              :    if (nspden == 2) then
     413              :      do ifft = 1, nfft
     414              : !      We change rhor for psolver call.
     415              :        tmpDown = rhor(ifft, 1) - rhonow(ifft, 2)
     416              :        tmpUp   = rhor(ifft, 2)
     417              :        rhor(ifft, 1) = tmpUp
     418              :        rhor(ifft, 2) = tmpDown
     419              :      end do
     420              :    end if
     421              : !  Make the density positive everywhere (but do not care about gradients)
     422              :    iwarn=0 ; opt_mkdenpos=0
     423              :    call mkdenpos(iwarn, nfft, nspden, opt_mkdenpos, rhor, xc_denpos)
     424              : !  do ispin=1,nspden
     425              : !  do ifft=1,nfft
     426              : !  rhor(ifft,ispin)=abs(rhor(ifft,ispin))+1.0d-20
     427              : !  end do
     428              : !  end do
     429              : 
     430              : !  Call Poisson solver, here rhor(:,1) will contain Vhartree at output
     431              : !  This does not compile, check mklocl_realspace where it do work.
     432              : !   call psolver(bndcode, datacode, me, nproc, n1i, &
     433              : !&   n2i,n3i, ixc, hgrid(1), hgrid(2), hgrid(3), &
     434              : !&   rhor, kernel, vxc, enhartr, enxc, envxc, 0.d0, .false., nspden)
     435              : 
     436              : !  PSolver work in place, we set back the rhor values.
     437              :    do ifft = 1, nfft, 1
     438              :      tmpPot     = rhor(ifft, 1)
     439              : !    Rhor total was saved in vhartr and current rhor(:,2) is down spin
     440              :      rhor(ifft, 1) = vhartr(ifft)
     441              :      if (nspden == 2) rhor(ifft, 2) = rhor(ifft, 1) - rhor(ifft, 2)
     442              :      vhartr(ifft)  = tmpPot
     443              :    end do
     444              :  end if
     445              : 
     446              : !Pass vhartr and vxc to BigDFT objects (useless?)
     447              : !if(usewvl==1) then
     448              : !  write(message, '(a,a,a,a)' ) ch10, ' rhotoxc_wvlpaw : but why are you copying me :..o('
     449              : ! call wvl_vhartr_abi2big(1,vhartr,wvl_den)
     450              : !  (this can be commented out, since we do not use denspot%v_xc
     451              : ! call wvl_vxc_abi2big(1,vxc,wvl_den)
     452              : !end if
     453              : 
     454              : !Compute vxcavg
     455              :  call mean_fftr(vxc, vxcmean, nfft, nfftot, nspden,mpi_comm_sphgrid=comm)
     456              :  vxcavg = vxcmean(1)
     457              : 
     458              : !Pass energies to wvl object:
     459              :  if(usewvl==1) then
     460              :    wvl_e%energs%eh  = enhartr
     461              :    wvl_e%energs%exc = enxc
     462              :    wvl_e%energs%evxc= envxc
     463              :  end if
     464              : 
     465              : !Nullify pointers and deallocate arrays
     466              :  if(test_nhat .and. .not. rest_hat_n_here) then
     467              : !  if(nspden==2) ABI_FREE(rhohat)
     468              :    ABI_FREE(rhohat)
     469              :    if(associated(rhohat)) nullify(rhohat)
     470              :  end if
     471              :  if( n3xccc>0 .and. .not. add_n_c_here) then
     472              :    if(usepaw==1) then
     473              :      ABI_FREE(rhocore)
     474              :    end if
     475              :  end if
     476              :  if(associated(rhocore))  nullify(rhocore)
     477              :  if(associated(pot_ion)) nullify(pot_ion)
     478              : 
     479              : #else
     480            0 :  BIGDFT_NOTENABLED_ERROR()
     481              :  if (.false.) write(std_out,*) nhatdim,nspden,n3xccc,nfft,icoulomb,ixc,nscforder,usewvl,&
     482              : & usexcnhat,usepaw,xclevel,rprimd(1,1),xc_denpos,enxc,envxc,enhartr,vxcavg,mpi_enreg%nproc,&
     483              : & wvl%h(1),wvl_den%symObj,wvl_e%energs,ngfft(1),xccc3d(1),nhat(1,1),rhor(1,1),vhartr(1),vxc(1,1)
     484              : #endif
     485              : 
     486              :  DBG_EXIT("COLL")
     487              : 
     488            0 : end subroutine psolver_rhohxc
     489              : !!***
     490              : 
     491              : !!****f* ABINIT/Psolver_hartree
     492              : !! NAME
     493              : !! Psolver_hartree
     494              : !!
     495              : !! FUNCTION
     496              : !! Given rho(r), compute Hartree potential considering the system as
     497              : !! an isolated one. This potential is obtained from the convolution
     498              : !! of 1/r and rho(r), treated in Fourier space. This method is a wrapper around
     499              : !! Psolver() developped for BigDFT.
     500              : !! It does not compute the xc energy nor potential. See psolver_rhohxc() to do it.
     501              : !! WARNING : the XC energy and potential computation capability has been
     502              : !! for spin-polarized case, as everything is done as if nspden=1
     503              : !!
     504              : !! INPUTS
     505              : !!  dtset <type(dataset_type)>=all input variables in this dataset
     506              : !!  mpi_enreg=MPI-parallelisation information.
     507              : !!  rhor(nfft,nspden)=electron density in real space in electrons/bohr**3
     508              : !!
     509              : !! OUTPUT
     510              : !!  enhartr=returned Hartree energy (hartree).
     511              : !!  vhartr(nfft)=Hartree potential.
     512              : !!
     513              : !! NOTE
     514              : !!  In PSolver, with nspden == 2, rhor(:,1) = density up and
     515              : !!                                rhor(:,2) = density down.
     516              : !!  But in ABINIT (dtset%usewvl != 1) rhor(:,1) = total density and
     517              : !!                                    rhor(:,2) = density up .
     518              : !!  In ABINIT (dtset%usewvl != 1), the same convention is used as in PSolver.
     519              : !!
     520              : !! SOURCE
     521              : 
     522            0 : subroutine psolver_hartree(enhartr, hgrid, icoulomb, me, mpi_comm, nfft, ngfft, nproc, &
     523            0 :      & nscforder, nspden, rhor, vhartr, usewvl)
     524              : 
     525              : #if defined HAVE_BIGDFT
     526              :  use BigDFT_API,     only : coulomb_operator
     527              :  use poisson_solver, only : H_potential
     528              : #endif
     529              : 
     530              :   !Arguments ------------------------------------
     531              :   !scalars
     532              :   integer, intent(in)           :: nfft, nspden, icoulomb, usewvl, mpi_comm, me, nproc, nscforder
     533              :   real(dp), intent(out)         :: enhartr
     534              :   !arrays
     535              :   integer, intent(in)    :: ngfft(3)
     536              :   real(dp),intent(in)    :: hgrid(3)
     537              :   real(dp),intent(in)    :: rhor(nfft,nspden)
     538              :   real(dp),intent(out)   :: vhartr(nfft)
     539              : 
     540              :   !Local variables-------------------------------
     541              : #if defined HAVE_BIGDFT
     542              :   !scalars
     543              :   character(len=500) :: message
     544              :   character(len = 1) :: datacode, bndcode
     545              :   !arrays
     546              :   real(dp), dimension(1) :: pot_ion_dummy
     547              :   type(coulomb_operator):: kernel
     548              : #endif
     549              : 
     550              : ! *********************************************************************
     551              : 
     552              : #if defined HAVE_BIGDFT
     553              : 
     554              :  if (icoulomb == 0) then
     555              : !  The kernel is built with 'P'eriodic boundary counditions.
     556              :    bndcode = 'P'
     557              :  else if (icoulomb == 1) then
     558              : !  The kernel is built with 'F'ree boundary counditions.
     559              :    bndcode = 'F'
     560              :  else if (icoulomb == 2) then
     561              : !  The kernel is built with 'S'urface boundary counditions.
     562              :    bndcode = 'S'
     563              :  end if
     564              : 
     565              :  if(nspden > 2 .and. usewvl/=0 )then
     566              :    write(message, '(a,a,a,i0)' )&
     567              : &   'Only non-spin-polarised or collinear spin is allowed for wavelets,',ch10,&
     568              : &   'while the argument nspden = ', nspden
     569              :    ABI_BUG(message)
     570              :  end if
     571              : 
     572              : !We do the computation.
     573              :  write(message, "(A,A,A,3I6)") "Psolver_hartree(): compute potential (Vhartree)...", ch10, &
     574              : & " | dimension:", ngfft(1:3)
     575              :  call wrtout(std_out, message,'COLL')
     576              : 
     577              :  if (usewvl == 0) then
     578              :    vhartr(:)  = rhor(:, 1)
     579              : 
     580              :    datacode = 'G'
     581              : !  This may not work with MPI in the planewave code...
     582              :  else
     583              :    if(nspden==1)vhartr(:)  = rhor(:, 1)
     584              :    if(nspden==2)vhartr(:)  = rhor(:, 1) + rhor(:, 2)
     585              : !  The data are 'D'istributed in the wavelet case or 'G'lobal otherwise.
     586              :    if (nproc > 1) then
     587              :      datacode = 'D'
     588              :    else
     589              :      datacode = 'G'
     590              :    end if
     591              :  end if
     592              : 
     593              : !We get the kernel.
     594              :  call psolver_kernel( hgrid, 2, icoulomb, me, kernel, mpi_comm, ngfft, nproc, nscforder)
     595              : 
     596              : 
     597              : !We attack PSolver with the total density contained in vhartr.
     598              : !This is also valid for spin-polarized (collinear and non-collinear)
     599              : !systems. Thus we enter nspden (last arg of PSolver) as being 1.
     600              : !Warning : enxc and evxc are meaningless.
     601              : ! call psolver(bndcode, datacode, me, nproc, ngfft(1), ngfft(2), ngfft(3),&
     602              : !& 0, hgrid(1), hgrid(2), hgrid(3), vhartr, kernel%co%kernel, pot_ion_dummy, &
     603              : !& enhartr, enxc, evxc, 0.d0, .false., 1)
     604              : 
     605              :  call H_potential(datacode,kernel,vhartr,pot_ion_dummy,&
     606              : & enhartr,zero,.false.)
     607              : 
     608              : 
     609              : #else
     610            0 :  BIGDFT_NOTENABLED_ERROR()
     611              :  if (.false.) write(std_out,*)  nfft,nspden,icoulomb,usewvl,mpi_comm,me,nproc,nscforder,enhartr,&
     612              : & ngfft(1),hgrid(1),rhor(1,1),vhartr(1)
     613              : #endif
     614              : 
     615            0 : end subroutine psolver_hartree
     616              : !!***
     617              : 
     618              : !!****f* ABINIT/psolver_kernel
     619              : !! NAME
     620              : !! psolver_kernel
     621              : !!
     622              : !! FUNCTION
     623              : !! Build, get or free the kernel matrix used by the Poisson solver to compute the
     624              : !! the convolution between 1/r and rho. The kernel is a saved variable. If
     625              : !! this routine is called for building while a kernel already exists, it is not
     626              : !! recomputed if all parameters (grid step and data size) are unchanged. Otherwise
     627              : !! the kernel is freed and recompute again. The build action has a returned variable
     628              : !! which is a pointer on the kernel. The get action also returns the kernel, or
     629              : !! NULL if none has been associated.
     630              : !!
     631              : !! INPUTS
     632              : !!  iaction=0 to free all kernel allocated array,
     633              : !!          1 to compute the kernel (parallel case),
     634              : !!          2 to get it (parallel case),
     635              : !!          3 to compute the kernel (sequential),
     636              : !!          4 to get the sequential kernel.
     637              : !!  rprimd(3,3)=dimensional primitive translations in real space (bohr)
     638              : !!
     639              : !! OUTPUT
     640              : !!  kernel= associated kernel on build (iaction = 1) and get action (iaction = 2).
     641              : !!
     642              : !! SOURCE
     643              : 
     644            0 : subroutine psolver_kernel(hgrid, iaction,  icoulomb, &
     645              : & iproc, kernel, mpi_comm, ngfft, nproc, nscforder)
     646              : 
     647              : #if defined HAVE_BIGDFT
     648              :  use BigDFT_API,     only  : coulomb_operator,nullify_coulomb_operator, &
     649              : &                            deallocate_coulomb_operator,mpi_environment
     650              :  use poisson_solver, only : pkernel_init,pkernel_set
     651              : #else
     652              :  use defs_wvltypes,  only : coulomb_operator
     653              : #endif
     654              : 
     655              : !Arguments ------------------------------------
     656              :   !scalars
     657              :   integer,intent(in) :: iaction, icoulomb, mpi_comm, nscforder, iproc, nproc
     658              :   !arrays
     659              :   integer, intent(in) :: ngfft(3)
     660              :   type(coulomb_operator),intent(inout)::kernel
     661              :   real(dp),intent(in) :: hgrid(3)
     662              : 
     663              : !Local variables-------------------------
     664              : #if defined HAVE_BIGDFT
     665              :   !scalars
     666              :   integer,parameter :: igpu=0 !no GPUs
     667              :   !arrays
     668              :   integer, save :: kernel_scfOrder
     669              :   integer, save :: kernel_icoulomb
     670              :   integer, save :: data_size(3) = (/ -2, -2, -2 /)
     671              :   real(dp), save :: kernel_hgrid(3)   ! Grid step used when creating the kernel.
     672              :   character(len = 1) :: geocode
     673              :   character(len=500) :: message
     674              :   integer :: current_size(3)
     675              :   type(coulomb_operator),save :: pkernel, kernelseq
     676              :   type(mpi_environment) :: mpi_env
     677              : #endif
     678              : 
     679              : ! *************************************************************************
     680              : 
     681              : #if defined HAVE_BIGDFT
     682              : 
     683              :  if (icoulomb == 0) then
     684              : !  The kernel is built with 'P'eriodic boundary counditions.
     685              :    geocode = 'P'
     686              :  else if (icoulomb == 1) then
     687              : !  The kernel is built with 'F'ree boundary counditions.
     688              :    geocode = 'F'
     689              :  else if (icoulomb == 2) then
     690              : !  The kernel is built with 'S'urface boundary counditions.
     691              :    geocode = 'S'
     692              :  end if
     693              :  current_size(:) = ngfft(1:3)
     694              : 
     695              : !Initialise kernel_array pointer.
     696              :  if (maxval(data_size) == -2) then
     697              :    call nullify_coulomb_operator(pkernel)
     698              :    call nullify_coulomb_operator(kernelseq)
     699              :  end if
     700              : 
     701              : !If iaction == 0, we free the kernel.
     702              :  if (iaction == 0) then
     703              :    if (associated(pkernel%kernel)) then
     704              :      write(message, "(A)") "Psolver_kernel() : deallocating pkernel..."
     705              :      call wrtout(std_out, message,'COLL')
     706              : 
     707              :      call deallocate_coulomb_operator(pkernel)
     708              :    end if
     709              :    if (associated(kernelseq%kernel)) then
     710              :      write(message, "(A)") "Psolver_kernel() : deallocating kernelseq..."
     711              :      call wrtout(std_out, message,'COLL')
     712              : 
     713              :      call deallocate_coulomb_operator(kernelseq)
     714              :    end if
     715              :    data_size = (/ -1, -1, -1 /)
     716              :    return
     717              :  end if
     718              : 
     719              : 
     720              : !Action is build or get. We check the sizes before doing anything else.
     721              : 
     722              : !!$!Get the size depending on wavelets calculations or not
     723              : !!$ if (dtset%usewvl == 0) then
     724              : !!$   hgrid(1) = rprimd(1, 1) / ngfft(1)
     725              : !!$   hgrid(2) = rprimd(2, 2) / ngfft(2)
     726              : !!$   hgrid(3) = rprimd(3, 3) / ngfft(3)
     727              : !!$
     728              : !!$ else
     729              : !!$   hgrid(:) = 0.5d0 * wvl%h(:)
     730              : !!$   current_size(1:3) = (/ wvl%Glr%d%n1i, wvl%Glr%d%n2i, wvl%Glr%d%n3i /)
     731              : !!$ end if
     732              : 
     733              : !Compute a new kernel if grid size has changed or if the kernel
     734              : !has never been computed.
     735              :  if ((iaction == 1 .and. .not. associated(pkernel%kernel))    .or. &
     736              : & (iaction == 3 .and. .not. associated(kernelseq%kernel)) .or. &
     737              : & kernel_icoulomb /= icoulomb  .or. &
     738              : & data_size(1)    /= current_size(1) .or. &
     739              : & data_size(2)    /= current_size(2) .or. &
     740              : & data_size(3)    /= current_size(3) .or. &
     741              : & kernel_hgrid(1) /= hgrid(1)        .or. &
     742              : & kernel_hgrid(2) /= hgrid(2)        .or. &
     743              : & kernel_hgrid(3) /= hgrid(3)        .or. &
     744              : & kernel_scfOrder /= nscforder) then
     745              :    write(message, "(A,A,A,3I6)") "Psolver_kernel() : building kernel...", ch10, &
     746              : &   " | data dimensions:", current_size
     747              :    call wrtout(std_out, message, 'COLL')
     748              : 
     749              :    if (iaction == 1 .or. iaction == 2) then
     750              :      if (associated(pkernel%kernel)) then
     751              :        call deallocate_coulomb_operator(pkernel)
     752              :      end if
     753              :      mpi_env%mpi_comm = mpi_comm
     754              :      mpi_env%iproc    = iproc
     755              :      mpi_env%nproc    = nproc
     756              :      mpi_env%igroup   = 0 ! no task groups
     757              :      mpi_env%ngroup   = 1 ! no task groups
     758              :      pkernel= pkernel_init(.True.,iproc,nproc,igpu,geocode,&
     759              : &     current_size,hgrid,nscforder, mpi_env = mpi_env)
     760              :      call pkernel_set(pkernel,.True.)
     761              :    end if
     762              : 
     763              :    if (iaction == 3 .or. iaction == 4) then
     764              :      if (associated(kernelseq%kernel)) then
     765              :        call deallocate_coulomb_operator(kernelseq)
     766              :      end if
     767              :      mpi_env%mpi_comm = mpi_comm
     768              :      mpi_env%iproc    = 0
     769              :      mpi_env%nproc    = 1
     770              :      mpi_env%igroup   = 0 ! no task groups
     771              :      mpi_env%ngroup   = 1 ! no task groups
     772              :      kernelseq= pkernel_init(.True.,iproc,nproc,igpu,geocode,&
     773              : &     current_size,hgrid,nscforder, mpi_env = mpi_env)
     774              :      call pkernel_set(kernelseq,.True.)
     775              :    end if
     776              : 
     777              : !  Storing variables which were used to make the kernel
     778              :    kernel_icoulomb = icoulomb
     779              :    data_size(:)    = current_size(:)
     780              :    kernel_hgrid(:) = hgrid(:)
     781              :    kernel_scfOrder = nscforder
     782              :  end if
     783              : 
     784              :  ! Shallow copy if kernel has been associated.
     785              :  if (iaction == 1 .or. iaction == 2) then
     786              :    kernel = pkernel
     787              :  end if
     788              :  if (iaction == 3 .or. iaction == 4) then
     789              :    kernel = kernelseq
     790              :  end if
     791              : 
     792              : #else
     793            0 :  BIGDFT_NOTENABLED_ERROR()
     794              :  if (.false.) write(std_out,*)  iaction,icoulomb,mpi_comm,nscforder,iproc,nproc,ngfft(1),kernel%co,hgrid(1)
     795              : #endif
     796              : 
     797            0 : end subroutine psolver_kernel
     798              : !!***
     799              : 
     800              : end module m_psolver
     801              : !!***
        

Generated by: LCOV version 2.3-1